Promise构造器中resolve在setTimeout内的事件循环工作机制解惑
问题解答
一、澄清你对Promise .then() 回调入队时机的误解
你核心的误区在于:.then() 的回调不会在调用 .then() 时直接进入微任务队列。实际逻辑是:
- 当调用
.then()时,如果Promise处于pending状态,回调会被暂存在Promise实例的回调列表中,不会立刻入队。 - 只有当Promise的状态变为
fulfilled或rejected时,对应的暂存回调才会被推入微任务队列等待执行。
对应到你代码里的第一个Promise:
- 同步执行构造器时,
setTimeout(() => resolve(3), 0)只是把一个宏任务(定时器回调)扔进了宏任务队列,此时Promise还是pending状态。 - 调用
.then()时,因为Promise是pending,所以这个(val) => console.log(val)回调被暂存起来,并没有进入微任务队列。 - 直到后续事件循环处理到定时器宏任务时,执行
resolve(3),把Promise状态改为fulfilled,这时候才会把之前暂存的.then()回调推入微任务队列。 - 所以当这个回调执行时,Promise已经有了resolved的值3,自然能打印出来。
二、完整代码执行流程拆解
我们一步步走一遍代码的执行顺序:
- 同步代码阶段:
- 执行第一个Promise构造器:打印
in here, 1,调用setTimeout把回调入宏任务队列,打印in here, 2,返回pending状态的Promise实例,调用其.then()并暂存回调。 - 执行第二个Promise构造器:打印
in here, 5,调用resolve(4)将Promise改为fulfilled状态,打印in here, 6,调用其.then(),此时因为Promise已resolved,回调被推入微任务队列。
- 执行第一个Promise构造器:打印
- 同步代码执行完毕,处理微任务队列:
- 微任务队列里只有第二个Promise的
.then()回调,执行它,打印4。微任务队列清空。
- 微任务队列里只有第二个Promise的
- 处理宏任务队列:
- 取出定时器回调执行:调用
resolve(3),将第一个Promise改为fulfilled状态,同时把之前暂存的.then()回调推入微任务队列。
- 取出定时器回调执行:调用
- 宏任务执行完毕,再次处理微任务队列:
- 执行第一个Promise的
.then()回调,打印3。
- 执行第一个Promise的
三、Node.js 微任务队列工作机制
Node.js的事件循环分为多个阶段(timers、pending callbacks、poll、check、close callbacks等),每个阶段处理对应的宏任务。而微任务队列的处理规则是:
- 微任务分为两个队列,优先级从高到低:
process.nextTick()队列:所有通过process.nextTick()添加的任务优先执行。- Promise微任务队列:包括
.then()/.catch()/.finally()的回调,以及queueMicrotask()添加的任务。
- 每个宏任务阶段执行完毕后,会先清空所有微任务队列:先把
process.nextTick队列的所有任务执行完,再执行Promise微任务队列的所有任务,全部执行完后才会进入下一个宏任务阶段。 - 注意:如果在微任务执行过程中又添加了新的微任务,这些新任务也会在当前微任务处理阶段被执行,直到微任务队列彻底清空。
内容的提问来源于stack exchange,提问作者lewislin
相关产品推荐
相关产品推荐

