关于事件循环代码段的随机结果

时间:2018-11-22 06:30:53

标签: javascript event-loop

我正在研究javascript事件循环,并且尝试了一些复杂的嵌套异步代码,其中之一使我非常复杂。代码段如下:

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解决事件循环中存在一些问题?

2 个答案:

答案 0 :(得分:0)

回调执行顺序并不是真正确定的。每当一个Promise解决时,执行schema.pre('findOneAndUpdate', function(next) { // this.email = this.email.toLowerCase() if (this.password === '') { return next() } else { const SALT_FACTOR = 5 return bcrypt.genSaltAsync(SALT_FACTOR).then((salt) => { return bcrypt.hashAsync(this.password, salt, null) }).then((hash) => { this.password = hash next() }).catch((err) => next(err)) } }) 链的任务就会被推送到Eventqueue上。计时器解析时也会发生同样的情况。当计时器同时运行时,如果它们彼此靠近,它们可能无法完全按照其启动顺序完成操作。

.then()

答案 1 :(得分:0)

您要结合两件事:Promise.resolvewindow.setTimeout。前者同步运行,并将已解决的项目立即放入队列。 window.setTimeout有不同的方法。一旦计时器到期,它将开始处理提供的功能。如您在第一个承诺中所使用的,将0用作window.setTimeout的延迟时间:

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

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

有关MDN的信息更易于阅读:Reasons for delays longer than specified

取决于浏览器/引擎,引擎可能正忙于(后台)任务,因此计时器受到限制。当您经历了自己时,可能会遇到不同的结果。最短调节时间为4ms(根据规格,但浏览器可以使用其他值)。最终结果是,节流计时器中的函数在另一个未被节流的计时器之后执行。