web中Promise.resolve().then(callback)比setTimeout(callback,0)更快的原因是什么
这篇文章给大家分享的是有关web中Promise.resolve().then(callback)比setTimeout(callback,0)更快的原因是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
一、实验
让我们尝试一个实验。什么执行得更快:立即解决的承诺或立即超时(也就是0毫秒超时)?
Promise.resolve(1).then(function resolve() {
console.log('Resolved!');
});
setTimeout(function timeout() {
console.log('Timed out!');
}, 0);
// logs 'Resolved!'
// logs 'Timed out!'
Promise.resolve(1)是一个静态函数,它返回一个立即解决的承诺。setTimeout(callback, 0)以0毫秒的延迟执行回调。
打开演示并检查控制台。您会注意到'Resolved!'首先记录的是 ,然后是'Timeout completed!'。立即解决的承诺比立即超时处理得更快。
承诺过程可能会更快,因为Promise.resolve(true).then(...)在setTimeout(..., 0)? 够公平的问题。
我们稍微改变一下实验的条件,setTimeout(..., 0)先调用:
setTimeout(function timeout() {
console.log('Timed out!');
}, 0);
Promise.resolve(1).then(function resolve() {
console.log('Resolved!');
});
// logs 'Resolved!'
// logs 'Timed out!'
打开演示并查看控制台。嗯……结果一样!
setTimeout(..., 0)之前被调用Promise.resolve(true).then(...)。但是,'Resolved!'仍然记录在'Timed out!'.
实验表明,在立即超时之前处理立即解决的承诺。最大的问题是……为什么?
2.事件循环
与异步 JavaScript 相关的问题可以通过调查事件循环来回答。让我们回顾一下异步 JavaScript 工作原理的主要组成部分。
注意:如果您不熟悉事件循环,我建议您在进一步阅读之前先观看此视频。
调用堆栈是一个 LIFO(后进先出)结构,用于存储代码执行期间创建的执行上下文。简单来说,调用堆栈执行函数。
Web API是异步操作(获取请求、承诺、计时器)及其回调等待完成的地方。
任务队列(也称为宏任务)是一个 FIFO(先进先出)结构,它保存准备执行的异步操作的回调。例如,超时的回调setTimeout()——准备执行——被排入任务队列。
作业队列(也称为微任务)是一个 FIFO(先进先出)结构,用于保存准备执行的承诺回调。例如,已履行的承诺的解决或拒绝回调在作业队列中排队。
最后,事件循环会永久监控调用堆栈是否为空。如果调用堆栈为空,则事件循环会查看作业队列或任务队列,并将任何准备执行的回调出列到调用堆栈中。
3. 作业队列 vs 任务队列
我们再从事件循环的角度来看这个实验。我会一步一步分析代码执行。
A) 调用栈执行setTimeout(..., 0)并调度一个定时器。timeout()回调存储在Web API 中:
setTimeout(function timeout() {
console.log('Timed out!');
}, 0);
Promise.resolve(1).then(function resolve() {
console.log('Resolved!');
});
B) 调用堆栈执行Promise.resolve(true).then(resolve)并安排承诺解决方案。resolved()回调存储在Web API 中:
setTimeout(function timeout() {
console.log('Timed out!');
}, 0);
Promise.resolve(1).then(function resolve() {
console.log('Resolved!');
});
C)承诺立即解决,计时器立即超时。因此,定时器回调timeout()被排入任务队列,promise 回调resolve()被排入作业队列:
D)现在是有趣的部分:事件循环优先于任务出列作业。事件循环resolve()从作业队列中取出承诺回调并将其放入调用堆栈中。然后调用堆栈执行承诺回调resolve():
setTimeout(function timeout() {
console.log('Timed out!');
}, 0);
Promise.resolve(1).then(function resolve() {
console.log('Resolved!');
});
'Resolved!' 记录到控制台。
E) 最后,事件循环将计时器回调timeout()从任务队列中出列到调用堆栈中。然后调用堆栈执行定时器回调timeout():
setTimeout(function timeout() {
console.log('Timed out!');
}, 0);
Promise.resolve(1).then(function resolve() {
console.log('Resolved!');
});
'Timed out!' 记录到控制台。
调用堆栈为空。脚本执行已完成。
4. 总结
为什么立即解决的承诺比立即计时器处理得更快?
由于事件循环优先级使作业队列(存储已履行的承诺的回调)中的作业优先于任务队列(存储超时setTimeout()回调)中的任务。
感谢各位的阅读!关于“web中Promise.resolve().then(callback)比setTimeout(callback,0)更快的原因是什么”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341