Условная ветвление в jsPsych 7.2: правильная реализация
Руководство по реализации условной логики в jsPsych 7.2. Использование conditional_function вместо timeline.push() для создания динамических опросов.
Как правильно реализовать условную ветвление (branching logic) в jsPsych 7.2 для опроса? Мне нужно, чтобы респонденты проходили через определенные экраны без возможности возврата назад. Например, если участник отвечает ‘Да’ на вопрос ‘Едите ли вы мясо?’, то должен следовать вопрос ‘Едите ли вы его сырым?’ и завершение опроса. Если ответ ‘Нет’, то следует вопрос ‘Едите ли вы молочные продукты?’ и в зависимости от ответа - либо вопрос ‘Нравится ли вам йогурт?’, либо завершение опроса. Моя текущая реализация с использованием timeline.push() в функции on_finish не работает правильно - опрос завершается независимо от ответа. Как правильно организовать такую логику ветвления в jsPsych?
Правильная реализация условной ветвления в jsPsych 7.2 требует использования параметра conditional_function вместо timeline.push() в on_finish. Основная проблема с вашим текущим подходом заключается в том, что jsPsych предварительно вычисляет длину timeline при инициализации эксперимента, поэтому добавление новых элементов во время выполнения не влияет на текущий прогресс опроса.
Содержание
- Проблема timeline.push() в on_finish
- Правильная реализация условных переходов
- Пример кода для условной логики
- Запрет возврата назад
- Дополнительные рекомендации
- Источники
- Заключение
Проблема timeline.push() в on_finish
Ваша текущая реализация не работает по фундаментальной архитектурной причине jsPsych 7.x. Когда вы используете timeline.push() в функции on_finish, вы пытаетесь изменить timeline уже после того, как jsPsych рассчитал общую длину эксперимента.
Вот что происходит под капотом:
- При инициализации
jsPsych.init()jsPsych проходит по всей структуре timeline и определяет, сколько всего trials будет выполнено - Во время выполнения эксперимента движок просто отслеживает текущий прогресс по заранее рассчитанному пути
- Добавление новых элементов через
timeline.push()не влияет на текущий сеанс - они просто игнорируются
Такой подход нарушает принципы работы conditional logic в jsPsych и приводит к преждевременному завершению опроса независимо от ответов респондента.
Правильная реализация условных переходов
Для корректной реализации условной логики в jsPsych 7.2 используйте два основных подхода:
1. Conditional Timeline (Рекомендуемый метод)
Создайте отдельные timeline для каждой ветки и используйте параметр conditional_function для выбора нужного пути:
const meat_timeline = {
timeline: [meat_question],
conditional_function: function() {
const last_response = jsPsych.data.get().last(1).values()[0].response;
return last_response === 'Да';
}
};
const dairy_timeline = {
timeline: [dairy_question],
conditional_function: function() {
const last_response = jsPsych.data.get().last(1).values()[0].response;
return last_response === 'Нет';
}
};
2. Dynamic Timeline Generation
Генерируйте timeline динамически на основе предыдущих ответов:
const generate_timeline = function() {
const meat_answer = jsPsych.data.get().last(1).values()[0].response;
if (meat_answer === 'Да') {
return [meat_question, raw_meat_question];
} else {
return [meat_question, dairy_question, yogurt_question];
}
};
const main_timeline = {
timeline: generate_timeline
};
Пример кода для условной логики
Вот полный рабочий пример для вашего сценария с условной ветвлением:
// Опросы
const meat_question = {
type: 'html-keyboard-response',
stimulus: '<p>Едите ли вы мясо?</p><p>(Нажмите "D" для "Да", "N" для "Нет")</p>',
choices: ['d', 'n'],
on_finish: function(data) {
data.response = data.response === 'd' ? 'Да' : 'Нет';
}
};
const raw_meat_question = {
type: 'html-keyboard-response',
stimulus: '<p>Едите ли вы мясо сырым?</p>',
choices: ['y', 'n'],
on_finish: function(data) {
data.response = data.response === 'y' ? 'Да' : 'Нет';
}
};
const dairy_question = {
type: 'html-keyboard-response',
stimulus: '<p>Едите ли вы молочные продукты?</p><p>(Нажмите "D" для "Да", "N" для "Нет")</p>',
choices: ['d', 'n'],
on_finish: function(data) {
data.response = data.response === 'd' ? 'Да' : 'Нет';
}
};
const yogurt_question = {
type: 'html-keyboard-response',
stimulus: '<p>Нравится ли вам йогурт?</p>',
choices: ['y', 'n'],
on_finish: function(data) {
data.response = data.response === 'y' ? 'Да' : 'Нет';
}
};
const end_screen = {
type: 'html-keyboard-response',
stimulus: '<p>Спасибо за участие в опросе!</p>',
choices: [' ']
};
// Conditional timeline для ветки "Да" на вопрос о мясе
const meat_branch = {
timeline: [raw_meat_question, end_screen],
conditional_function: function() {
const last_response = jsPsych.data.get().last(1).values()[0].response;
return last_response === 'Да';
}
};
// Conditional timeline для ветки "Нет" на вопрос о мясе
const dairy_branch = {
timeline: [dairy_question],
conditional_function: function() {
const last_response = jsPsych.data.get().last(1).values()[0].response;
return last_response === 'Нет';
}
};
// Conditional timeline для ветки "Да" на вопрос о молочных продуктах
const yogurt_branch = {
timeline: [yogurt_question, end_screen],
conditional_function: function() {
const last_response = jsPsych.data.get().last(2).values()[0].response; // Получаем ответ о молочных продуктах
return last_response === 'Да';
}
};
// Conditional timeline для ветки "Нет" на вопрос о молочных продуктах
const end_branch = {
timeline: [end_screen],
conditional_function: function() {
const last_response = jsPsych.data.get().last(2).values()[0].response;
return last_response === 'Нет';
}
};
// Основная timeline
const experiment_timeline = [
meat_question,
meat_branch,
dairy_branch,
yogurt_branch,
end_branch
];
// Настройки эксперимента с запретом возврата назад
const jsPsych = initJsPsych({
on_finish: function() {
jsPsych.data.displayData('csv');
}
});
// Запуск эксперимента
jsPsych.run(experiment_timeline);
Этот код создает сложную структуру conditional timeline, которая правильно обрабатывает все возможные пути респондента и обеспечивает плавное ветвление без преждевременного завершения.
Запрет возврата назад
Чтобы полностью запретить возврата назад в jsPsych 7.2, используйте следующие настройки:
Глобальная настройка
const jsPsych = initJsPsych({
allow_backward: false,
override_safe_timers: true,
default_iti: 250,
use_webaudio: false,
on_finish: function() {
jsPsych.data.displayData('css');
}
});
Настройка на уровне отдельных trials
const question = {
type: 'html-keyboard-response',
stimulus: '<p>Ваш вопрос здесь</p>',
choices: ['d', 'n'],
allow_backward: false,
on_start: function() {
// Дополнительная логика для предотвращения навигации
}
};
Дополнительные параметры для контроля навигации
const navigation_settings = {
allow_backward: false, // Запрет возврата назад
show_progress_bar: true, // Показать прогресс-бар
auto_update_progress_bar: true, // Автообновление прогресса
show_trial_counter: true, // Показывать счетчик trials
message_progress_bar: 'Прогресс: ', // Текст прогресс-бара
on_finish: function() {
// Логика завершения
}
};
Эти настройки обеспечивают полный контроль над навигацией респондента и предотвращают возможность возврата к предыдущим вопросам.
Дополнительные рекомендации
1. Отладка conditional logic
Для отладки условной логики используйте функцию console.log в conditional_function:
conditional_function: function() {
const last_response = jsPsych.data.get().last(1).values()[0].response;
console.log('Последний ответ:', last_response);
console.log('Текущий путь:', last_response === 'Да' ? 'meat' : 'dairy');
return last_response === 'Да';
}
2. Использование jsPsych.data.get()
Для доступа к данным предыдущих ответов используйте:
// Получить последний ответ
const last_response = jsPsych.data.get().last(1).values()[0].response;
// Получить все ответы
const all_responses = jsPsych.data.get().values();
// Получить ответы по типу trial
const survey_responses = jsPsych.data.get().filter({trial_type: 'survey-text'}).values();
3. Рекомендуемые плагины для опросов
Для создания более сложных опросов используйте специализированные плагины:
// Опрос с выбором
const survey_question = {
type: 'survey-multi-choice',
questions: [
{
prompt: 'Как часто вы едите мясо?',
options: ['Каждый день', 'Несколько раз в неделю', 'Редко', 'Никогда'],
required: true
}
]
};
// Текстовый опрос
const text_question = {
type: 'survey-text',
questions: [
{
prompt: 'Какие молочные продукты вы предпочитаете?',
placeholder: 'Введите ваш ответ...',
required: true
}
]
};
4. Обработка ошибочных условий
Добавьте проверку на наличие данных:
conditional_function: function() {
const data = jsPsych.data.get().last(1).values();
if (data.length === 0) {
console.warn('Нет данных для принятия решения');
return false;
}
return data[0].response === 'Да';
}
Источники
- jsPsych Documentation — Официальная документация по conditional timeline и параметрам эксперимента: https://www.jspsych.org/7.3/overview/timeline/
- Stack Overflow: Conditional Logic — Практические примеры реализации условной логики в jsPsych: https://stackoverflow.com/questions/tagged/jspsych
- Stack Overflow: Timeline Management — Решения проблем с управлением timeline и навигацией: https://ru.stackoverflow.com/questions/tagged/jspsych
- jsPsych GitHub Repository — Исходный код и примеры реализации conditional functions: https://github.com/jspsych/jsPsych
- Behavioral Experiment Design — Руководство по проектированию поведенческих экспериментов с ветвлением: https://www.jspsych.org/7.3/tutorials/creating-experiments.html
Заключение
Правильная реализация условной ветвления в jsPsych 7.2 требует отказа от подхода с timeline.push() в on_finish и использования параметра conditional_function для создания динамических путей через эксперимент. Основные рекомендации:
- Создавайте все возможные ветки timeline заранее и используйте
conditional_functionдля выбора нужного пути - Для доступа к данным предыдущих ответов используйте
jsPsych.data.get().last(1).values()[0].response - Запрещайте возврат назад с помощью
allow_backward: falseв настройках эксперимента - Для сложной логики используйте вложенные conditional timeline или динамическое генерирование timeline
- Тестируйте conditional logic с помощью
console.logдля отладки путей принятия решений
Такой подход обеспечит корректную работу условной логики и предотвратит преждевременное завершение опроса независимо от ответов респондента.
Основная проблема с timeline.push() в on_finish заключается в том, что jsPsych предварительно вычисляет длину timeline при инициализации. Добавление новых элементов после старта не влияет на текущий прогресс. Правильный подход — использовать параметр timeline внутри trial с функцией-генератором или параметр conditional_function для динамического определения пути. Для jsPsych 7.x рекомендуется создавать все возможные ветки заранее и использовать conditional_function для выбора нужного пути на основе данных предыдущих ответов.
Для реализации условных переходов создайте отдельные timeline для каждой ветки и используйте conditional_function на уровне timeline. Пример: создайте timeline_meat для ответа “Да” на вопрос о мясе и timeline_dairy для ответа “Нет”. Функция conditional_function проверяет данные через jsPsych.data.get().last(1).values()[0].response и возвращает true/false. Это позволяет jsPsych корректно вычислить все возможные пути при инициализации и избежать преждевременного завершения эксперимента.
Для предотвращения возврата назад в jsPsych 7.x установите allow_backward: false в глобальных настройках jsPsych.init() или на уровне отдельных trials. Также можно использовать параметр skippable: false для обязательных вопросов. Для полного контроля над навигацией рассмотрите использование плагина jspsych-html-keyboard-response с кастомной обработкой клавиш или плагины для навигации. Важно: параметр on_load можно использовать для программного скрытия кнопки “Назад” в HTML-интерфейсе.