Тестирование с использованием setTimeout(fn, 0). Что делает этот фрагмент тестового кода?

Это фрагмент из файла модульного теста, в котором используется jest. Функция синтаксического анализа возвращает обещание после завершения синтаксического анализа... Но я не могу понять использование этого логического флага (completedAsyncDummyTask).

it("parse is a promise that resolves with parser output", async () => {
  const parser = new Parser();
  let completedAsyncDummyTask = false;

  setTimeout(() => {
    completedAsyncDummyTask = true;
  }, 0);
  
  ...
  const test = await parser.parse(path.resolve(__dirname, "file.xyz"));
  expect(completedAsyncDummyTask).toBe(true);
  ...

});

Любые идеи?

Заранее спасибо.

Это... тест интересный. Я понимаю, почему вы спросили об этом.

T.J. Crowder 17.05.2022 14:57

Отвечает ли это на ваш вопрос? Почему setTimeout(fn, 0) иногда полезен?

Cristian Traìna 17.05.2022 14:57

@CristianTraìna - я думаю, что это больше о взаимодействии между выполнением обещаний и взаимодействием между используемой для него очередью микрозадач и очередью макрозадач, используемой для обратных вызовов таймера.

T.J. Crowder 17.05.2022 14:59
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Сравнение структур данных: Массивы и объекты в Javascript
Сравнение структур данных: Массивы и объекты в Javascript
Итак, вы изучили основы JavaScript и хотите перейти к изучению структур данных. Мотивация для изучения/понимания Структур данных может быть разной,...
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Прошлая статья была первой из цикла статей о создании системы электронной коммерции с использованием Keystone.js, и она была посвящена главным образом...
Приложение для отслеживания бюджета на React js для начинающих
Приложение для отслеживания бюджета на React js для начинающих
Обучение на практике - это проверенная тема для достижения успеха в любой области. Если вы знаете контекст фразы "Практика делает человека...
Стоит ли использовать React в 2022 году?
Стоит ли использовать React в 2022 году?
В 2022 году мы все слышим о трендах фронтенда (React, Vue), но мы не знаем, почему мы должны использовать эти фреймворки, когда их использовать, а...
1
3
33
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не могу представить, какова была бы цель теста. Я могу сказать вам, что он делает, но не почему.

Он проверяет, выполнил ли процесс parser.parse(path.resolve(__dirname, "file.xyz")) свое обещание, разрешив хотя бы один цикл через основную («макро») очередь задач, а не просто выполняя всю свою работу в очереди микрозадач, используемой при выполнении обещания.

Если обещание выполняется сразу, у основной очереди задач никогда не будет возможности запуститься до того, как запустится код, использующий await:

(async () => {
    setTimeout(() => {
        console.log("This comes second because it queues a macrotask");
    }, 0);
    await Promise.resolve();
    console.log("This comes first because the promise fulfillment never allowed the macro task queue to be processed.");
})();

Но если это не так, основная очередь задач может быть обработана хотя бы один раз, что дает этому обратному вызову таймера возможность установить переменную.

Наличие теста говорит о том, что в приложении есть какой-то код, основанный на таком поведении, что было бы довольно странно. Еще более странно, что нет никакого комментария, объясняющего столь малопонятный тест.


У вас может возникнуть соблазн подумать, что, поскольку Promise.resolve возвращает выполненное обещание, await вообще ничего не делает, и этот код просто выполняется синхронно. Это неправда, даже ожидание выполненного обещания включает задержку последующего кода в наименее до тех пор, пока очередь микрозадач не зациклится, как мы можем видеть здесь:

let run = true;
let ticks = 0;
(async () => {
    while (run) {
        await Promise.resolve();
        ++ticks;
    }
})();
(async () => {
    setTimeout(() => {
        console.log(`This comes second because it queues a macrotask`);
    }, 0);
    console.log(`Before: ticks = ${ticks}`);
    await Promise.resolve();
    console.log(`After:  ticks = ${ticks}`);
    console.log("This comes first because the promise fulfillment never allowed the macro task queue to be processed.");
    run = false;
})();

Я согласен с такой интерпретацией, вероятно, автор хотел проверить, действительно ли parse было async. Если бы код parse был похож на return Promise.resolve(parsedObject), тест провалился бы. Мы можем просто подумать, в каких сценариях тест не проходит, и попытаться выяснить,

Cristian Traìna 17.05.2022 15:02

@CristianTraìna - Да, или он полностью полагался только на цепочку уже выполненных обещаний. Странный тест однако. :-)

T.J. Crowder 17.05.2022 15:06

Другие вопросы по теме