You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将JsPsych实验数据从HTML导出为CSV失败求助

问题:jsPsych实验结束后弹出数据网页而非下载CSV文件

我一直在尝试把通过脚本运行的HTML实验数据保存为CSV文件到本地,但实验结束后总是弹出显示所有数据的新网页,而非下载CSV文件。我怀疑问题出在var jsPsych和var today这两个变量上,请问哪里操作有误?

<!DOCTYPE html>
<html>
  <head>
    <title>My experiment</title>
    <script src="https://unpkg.com/jspsych@7.2.3"></script>
    <script src="https://unpkg.com/@jspsych/plugin-html-keyboard-response@1.1.1"></script>
    <script src="https://unpkg.com/@jspsych/plugin-survey-multi-choice@1.1.1"></script>
    <link href="https://unpkg.com/jspsych@7.2.3/css/jspsych.css" rel="stylesheet" type="text/css" />
  </head>
  <body></body>
  <script>
/* initialize jsPsych */

/*var jsPsych = initJsPsych();*/
var jsPsych = initJsPsych({
        timeline: timeline,
        show_progress_bar: true,
        override_safe_mode: true,
        on_finish: function() {
            jsPsych.data
                .get()
                .localSave(
                    'csv',
                    'ekstra.html'
                );
        },
    });

var today = new Date();
    jsPsych.data.addProperties({
        date: ("0" + today.getDate()).slice(-2) + '-' + ("0" + (today.getMonth() + 1)).slice(-2) + '-' + today.getFullYear(),
        time: today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds(),
    });

/* create timeline */
var timeline = [];

// generate a random subject ID with 15 characters
var subject_id = jsPsych.randomization.randomID(6);

// this adds a property called 'subject' to every trial
jsPsych.data.addProperties({
  subject: subject_id,
});

var time_limit = 10000;
var start_time2;
var end_test_timer;
var trial_count = 0;
var n_trials = 7;
var counter2 = 1;

var sproglyde = {
  type: jsPsychSurveyMultiChoice,
  data: { sproglyde_test: 'Sproglyde' },
  questions: [
  {
      prompt: "<p>Vælg det 'ord' der lyder som et rigtigt dansk ord.</p><p>Vælg ordet (gæt evt.):</p>", 
      name: 'Sproglyd1', 
      options: ['sbese', 'sbuse', 'sbise', 'befse'], 
      required: true
    }, 
    {
      prompt: "Vælg ordet (gæt evt.):", 
      name: 'Sproglyd2', 
      options: ['sigam', 'sigar', 'sigur', 'sigat'], 
      required: true
    },
    {
      prompt: "Vælg ordet (gæt evt.):", 
      name: 'Sproglyd3', 
      options: ['nåmmer', 'nymmer', 'måmmer', 'fåmmer'], 
      required: true
    }
  ],
    on_load: function() {
                trial_count++;
                // we need to set up the timer to end the current timeline after a certain duration, but only on the first trial
                if (trial_count > 0) {
                    start_time2 = performance.now();
                    var end_test_timer = setTimeout(function() {
                        // this stuff is just for testing
                        var end_time = performance.now();
                        var elapsed_time = end_time - start_time2;
                        console.log("elapsed time: ", elapsed_time);
                        // this function ends the current trial 
                        jsPsych.finishTrial({status: "ended early"});
                    }, time_limit);
                }
            }, 
            on_finish: function() {
                counter2++;
                // we also need to cancel the setTimeout timer if the person gets all the way through the timeline before 
                // time_limit is reached, otherwise endCurrentTimeline will fire during the next timeline - not good!!
                if (trial_count == n_trials) {
                    clearTimeout(end_test_timer);
                }
                    }
};
timeline.push(sproglyde);


var Ordforråds = {
  type: jsPsychSurveyMultiChoice,
  data: { ordforraad_test: 'ordforraad' },
  questions: [
    {
      prompt: "<p>Vælg det ord som findes på dansk. Tænk ikke for længe. Du er velkommen til at gætte, hvis du ikke kender svaret</p>", 
      name: 'Ordforråd1', 
      options: ['gis', 'gim', 'git'], 
      required: true
    }, 
    {
      prompt: "Vælg ordet (gæt evt.):", 
      name: 'Ordforråd2', 
      options: ['trokæ', 'troklæ', 'tropæ'], 
      required: true
    }, 
    {
      prompt: "Vælg ordet (gæt evt.):", 
      name: 'Ordforråd3', 
      options: ['tights', 'tigts', 'kights'], 
      required: true
    }
  ],
};
timeline.push(Ordforråds);

/* run the experiment */
jsPsych.run(timeline);

    </script>
</html>

问题分析与修复方案

1. 核心问题:CSV文件名后缀错误

你在localSave方法里指定的文件名是'ekstra.html',浏览器会把这个文件识别为HTML类型,因此直接打开而非触发下载。必须把后缀改成.csv:

jsPsych.data
    .get()
    .localSave(
        'csv',
        'ekstra.csv' // 从.html改为.csv
    );

2. 初始化jsPsych时的时间线变量未定义

调用initJsPsych时传入了timeline: timeline,但此时timeline还未声明(后续才定义var timeline = []),会导致初始化错误。应移除该参数,因为后续已通过jsPsych.run(timeline)指定运行的时间线:

var jsPsych = initJsPsych({
        // 移除 timeline: timeline 这一行
        show_progress_bar: true,
        override_safe_mode: true,
        on_finish: function() {
            jsPsych.data
                .get()
                .localSave('csv', 'ekstra.csv');
        },
    });

3. 定时器变量作用域问题

在sproglyde的on_load函数里,用var end_test_timer重新声明变量,导致on_finish里的clearTimeout无法访问正确的定时器ID。需去掉on_load里的var,直接使用全局声明的end_test_timer:

on_load: function() {
    trial_count++;
    if (trial_count > 0) {
        start_time2 = performance.now();
        // 去掉var,直接赋值给全局变量
        end_test_timer = setTimeout(function() {
            var end_time = performance.now();
            var elapsed_time = end_time - start_time2;
            console.log("elapsed time: ", elapsed_time);
            jsPsych.finishTrial({status: "ended early"});
        }, time_limit);
    }
},

4. 额外优化:日期时间格式的引号问题

代码中"0"使用了中文引号,虽浏览器可能兼容,但建议改为英文双引号,避免潜在语法问题:

date: ("0" + today.getDate()).slice(-2) + '-' + ("0" + (today.getMonth() + 1)).slice(-2) + '-' + today.getFullYear(),
time: today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds(),

内容的提问来源于stack exchange,提问作者carolinehommel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:00:58