Тестирование с использованием 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
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
33
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

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

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

(async () => {
    setTimeout(() => {
        console.info("This comes second because it queues a macrotask");
    }, 0);
    await Promise.resolve();
    console.info("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.info(`This comes second because it queues a macrotask`);
    }, 0);
    console.info(`Before: ticks = ${ticks}`);
    await Promise.resolve();
    console.info(`After:  ticks = ${ticks}`);
    console.info("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

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