我知道setTimeout()
内部的回调函数会一直等待,直到它所连接的计时器到期,并被推入回调队列。另一方面,一个promise一旦被满足或拒绝,它的回调就会被推入一个微任务队列,这个队列具有更高的优先级。
我的问题是哪一次更快:promise中的setTimeout
或简单的setTimeout
。如果前一个不再放在微任务队列中,为什么setTimeout
单独首先运行,而不是相反?
setTimeout(() => {
console.log('timeout');
}, 1000);
let promise = new Promise(function(resolve, reject) {
// This is run automatically, let's run resolve after 1 second
setTimeout(() => resolve('promise!'), 1000);
});
promise.then(
(result) => console.log(result),
(err) => console.log(error)
);
// output: timeout -> promise || and not || promise -> timeout
现在让我们假设我忘记了1秒的延迟,现在promise总是首先出现,因为在微任务队列中调度的回调具有更高的优先级
setTimeout(() => {
console.log('timeout');
}, 0);
let promise = new Promise(function(resolve, reject) {
// This is run automatically, let's run resolve after 1 second
// setTimeout(() => resolve('promise!'), 1000);
resolve('');
});
promise.then(() => {
console.log('promise');
});
2条答案
按热度按时间tez616oj1#
setTimeout
是以一种方式实现的,它意味着在最小给定延迟之后执行,并且一旦浏览器的线程可以自由执行它。因此,例如,如果您为延迟参数指定0值,并且您认为它会“立即”执行,那么它不会。它会,更准确地说,在下一个事件循环中运行(这是事件循环的一部分-负责执行代码的并发模型)。让我们以延迟值为0为例。
setTimeout
总是首先记录它的结果,因为它肯定会在下一个事件周期中执行。另一方面,promise中的
setTimeout
将有2个事件周期,直到控制台日志执行(一个用于promise resolve,另一个用于setTimeout函数中的回调)。请阅读比指定时间更长的延迟原因-https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
关于JS事件循环的更多信息-https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
y4ekin9u2#
关键是
每次任务退出时,事件循环都会检查任务是否将控制权返回给其他JavaScript代码。如果没有,则会运行微任务队列中的所有微任务。
在下面的第一个示例中,一旦执行主程序的任务退出,由于第二次setTimeout,promise尚未解析,因此没有任何微任务需要处理。然后任务队列被处理,因此首先记录'timeout'。之后,处理第二次setTimeout并解析promise,然后在控制台中打印解析结果。
而在第二个示例中,promise在执行主程序的任务退出后被解析,因此微任务队列首先被处理并记录'promise'。然后任务队列被处理并记录'timeout'。
我强烈推荐阅读这篇文章,这有助于我深入了解任务队列和微任务队列的工作原理。