使用 setTimeout(fn, 0) 进行测试。这段测试代码的作用是什么?

Testing using setTimeout(fn, 0). What this snippet of testing code does?

这是使用 jest 的单元测试文件的片段。解析函数returns解析完成后的一个Promise... 但我无法理解该布尔标志 (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);
  ...

});

有什么想法吗?

提前致谢。

我无法想象测试的目的是什么。我可以告诉你它在做什么,但不能告诉你为什么。

它正在检查 parser.parse(path.resolve(__dirname, "file.xyz")) 进程是否履行了它的承诺,同时允许至少一个循环通过主(“宏”)任务队列,而不仅仅是在 micro-task 中完成所有工作承诺履行使用的队列。

如果承诺立即得到履行,主任务队列永远没有机会 运行 在代码使用 await 之前 运行s:

(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 returns 已兑现诺言,那么 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;
})();