"return Promise.resolve()" 如何影响 JavaScript 事件循环?

How does "return Promise.resolve()" affect the JavaScript Event loop?

我使用 Javascript 有一段时间了,我了解 javascript-event-loop 的工作原理。但是,我遇到了一个对我来说完全没有意义的案例。 考虑以下代码:

setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');

我期望这个输出:

3
1
2

但是,我 运行 它在 chrome js 控制台上,我得到以下信息:

3
2
1

问题:不应该 "Promise.resolve().then(fn)" 立即调用函数,或者将函数执行过程插入到事件循环的末尾 - 'setTimeout' 的工作方式 - 是吗我缺少什么?

setTimeout 遵循一组微妙的规则。例如,在一些浏览器上,最小超时为 4ms, not 0ms.

你是正确的,Promise 不会立即执行,而是等待一个干净的堆栈到 运行。

还有一些技巧,例如添加标签以强制将某些内容撞到事件循环的顶部。查看 setImmediate 浏览器的 polyfill

浏览器实现多个 job/task 队列。 The spec requires implementations to maintain two queues:

  1. 脚本队列
  2. 承诺队列

很可能还有一个 TimerQueue(HTML DOM 任务队列)也适用于 HTML DOM Level 2 Timer 规范。这些是在运行时填充的每个 FIFO 队列,最终是 the event loop queue。按照您的代码示例:

setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');
  • 第 1 行(可能)推送到 TimerQueue(HTML DOM 任务队列)
  • 第 2 行推送到 承诺队列
  • 第3行入栈并立即执行 (完成)

一旦堆栈为空,每个队列将排空直到为空。在您的示例中,Promise 队列首先清空,然后 TimerQueue 最后清空。

这可以通过稍微扩展您的示例来进一步证明:

setTimeout(()=> console.log('second from final')); // <-- first item in TimerQueue
Promise.resolve('whatever').then(()=>console.log('2')); //<-- first time in PromiseQueue
setTimeout(()=> console.log('just prior to final')); // <-- second item in TimerQueue
Promise.resolve('whatever').then(()=>console.log('1')); //<-- second item in PromiseQueue
setTimeout(()=> console.log('final')); // <-- third item in ScriptQueue 
console.log('3'); // <-- synchrounous function call placed onto the stack, executed immediately

您应该注意,不能保证执行顺序。规范没有定义队列的执行顺序:

This specification does not define the order in which multiple Job Queues are serviced. An ECMAScript implementation may interweave the FIFO evaluation of the PendingJob records of a Job Queue with the evaluation of the PendingJob records of one or more other Job Queues.

编辑

在与 Bergi 讨论(如下)之后,我指出浏览器实现也可能创建其他队列。与此 post 相关的最有可能的队列是一个 TimerQueue 作为任务队列,其中包含 HTML DOM 规范的计时器任务。