首页 > 解决方案 > 关于事件循环代码片段的随机结果

问题描述

我正在研究 javascript 事件循环,我尝试了一些复杂的嵌套异步代码,其中一个让我非常复杂。代码片段如下:</p>

console.log(1);
new Promise((resolve, reject) => {
    console.log(2);
    resolve();
}).then(() => {
    setTimeout(() => { console.log(3) }, 0);
});
setTimeout(() => {
    new Promise((resolve, reject) => {
        console.log(4);
        resolve();
    }).then(() => { console.log(5) });
});

结果有时是 1 - 2 - 4 - 5 - 3,有时是 1 - 2 - 4 - 3- 5。

它在浏览器环境和节点环境中执行相同的操作。

也许我的代码写错了,或者 V8 解决事件循环存在一些问题?

标签: javascriptevent-loop

解决方案


您正在结合两件事:Promise.resolvewindow.setTimeout. 前者同步运行并立即将已解决的项目放入队列中。然而window.setTimeout,有一个不同的方法。一旦计时器到期,它就会开始处理提供的函数。当使用你在第一个承诺中使用0的延迟时:window.setTimeout

setTimeout(() => { console.log(3) }, 0);

那么它并不意味着“立即运行”。更多的是“尽快运行此功能”。这可以更改,因为计时器正在被浏览器限制。如果您在阅读某些规范时没有问题,您可以阅读timer-initialisation-steps以了解它是如何被详细初始化的。

在 MDN 上有一个更容易阅读的信息:延迟时间超过指定的原因

依赖于浏览器/引擎,引擎可能正忙于(后台)任务,因此计时器会受到限制。正如您亲身经历的那样,在某些情况下您会得到不同的结果。最小限制时间是(根据规范,但浏览器可以使用不同的值)4 毫秒。最终结果是节流计时器中的函数在另一个没有被节流的计时器之后执行。


推荐阅读