为什么 Promise 比setTimeout() 快?

本文探讨了Promise.resolve与setTimeout(0)的执行顺序,揭示了JavaScript事件循环的工作原理。通过实验展示了即使setTimeout设为0毫秒,Promise的微任务也会优先于setTimeout的宏任务执行。解释了任务队列和作业队列在异步执行中的角色,强调了微任务在事件循环中的优先级。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.测试

我们来做个实验。哪个执行得更快:立即解决的 Promise 还是立即setTimeout(也就是0毫秒的setTimeout)?

 
Promise.resolve(1).then(function resolve() {
  console.log('Resolved!');
});

setTimeout(function timeout() {
  console.log('Timed out!');
}, 0);

// 'Resolved!'
// 'Timed out!'
 

promise.resolve(1)是一个静态函数,它返回一个立即解析的promise。setTimeout(callback, 0)以0毫秒的延迟执行回调函数。

我们可以看到先打印'Resolved!',再打印Timeout completed!,立即解决的 promise 比立即setTimeout更快。

是因为Promise.resolve(true).then(...)在setTimeout(..., 0)之前被调用了,所以 Promise 过程会更快吗? 公平的问题。

所以,我们稍微更改一下实验条件,然后先调用setTimeout(..., 0):

setTimeout(function timeout() {
  console.log('Timed out!');
}, 0);

Promise.resolve(1).then(function resolve() {
  console.log('Resolved!');
});

// 'Resolved!'
// 'Timed out!'

setTimeout(..., 0)在Promise.resolve(true).then(...)之前被调用。但,还是先打印Resolved!在打印'Timed out!'。

这是为啥呢?

 

2.事件循环

与异步 js 相关的问题可以通过研究事件循环来回答。我们回顾一下异步 js 工作方式的主要组成部分。

调用堆栈是一个LIFO(后进先出)结构,它存储在代码执行期间创建的执行上下文。简单地说,调用堆栈执行这些函数。

Web api是异步操作(fetch 请求、promise、计时器)及其回调等待完成的地方。

task queue (任务队列)是一个FIFO(先进先出)结构,它保存准备执行的异步操作的回调。例如,超时的setTimeout()的回调函数或准备执行的单击按钮事件处理程序都在任务队列中排队。

job queue (作业队列)是一个FIFO(先入先出)结构,它保存准备执行的promise 的回调。例如,已完成的承诺的resolve或reject回调被排在作业队列中。

最后,事件循环永久监听调用堆栈是否为空。如果调用堆栈为空,则事件循环查看作业队列或任务队列,并将准备执行的任何回调分派到调用堆栈中。

 

3.作业队列与任务队列

我们从事件循环的角度来看这个实验,我将对代码执行进行一步一步的分析。

A)调用堆栈执行setTimeout(..., 0)并计划一个计时器, timeout()回调存储在Web API中:

B)调用堆栈执行 Promise.resolve(true).then(resolve)并安排一个 promise 解决方案。 resolved()回调存储在Web API中:

C)promise 立即被解析,同时计时器也立即执行。这样,定时器回调timeout()进入任务队列,promise回调resolve()进入作业队列

D)现在是有趣的部分:作业队列(微任务)优先级高于任务队列(宏任务)。 事件循环从作业队列中取出promise回调resolve()并将其放入调用堆栈中。 然后,调用堆栈执行promise回调resolve():

E)最后,事件循环将计时器回调timeout()从任务队列中出队到调用堆栈中。 然后,调用堆栈执行计时器回调timeout():

调用堆栈为空,已完成脚本的执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值