我正在研究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解决事件循环中存在一些问题?
答案 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.resolve
和window.setTimeout
。前者同步运行,并将已解决的项目立即放入队列。 window.setTimeout
有不同的方法。一旦计时器到期,它将开始处理提供的功能。如您在第一个承诺中所使用的,将0
用作window.setTimeout
的延迟时间:
setTimeout(() => { console.log(3) }, 0);
那么这并不意味着“立即运行”。更多的是“尽快运行此功能”。这可以更改,因为浏览器正在限制计时器。如果您在阅读某些规范时没有问题,可以阅读timer-initialisation-steps
以了解其详细初始化方式。
有关MDN的信息更易于阅读:Reasons for delays longer than specified
取决于浏览器/引擎,引擎可能正忙于(后台)任务,因此计时器受到限制。当您经历了自己时,可能会遇到不同的结果。最短调节时间为4ms(根据规格,但浏览器可以使用其他值)。最终结果是,节流计时器中的函数在另一个未被节流的计时器之后执行。