JavaScript事件循环中Promise.then与queueMicrotask执行顺序问题求教
JavaScript事件循环微任务执行规则说明
首先明确3个核心底层规则:
- 所有微任务(Promise.then回调、queueMicrotask回调等)优先级完全相同,微任务队列遵循先进先出的执行顺序
- 同步代码执行栈清空后,会持续执行微任务队列中的所有任务直到队列为空,才会处理宏任务;单个微任务执行过程中新增的微任务,会追加到微任务队列末尾,在本次微任务清空流程内执行
- Promise的then回调会在其所属Promise状态变为resolved/rejected后立刻加入微任务队列;链式调用的then回调,会等前一个then的回调执行完毕、返回的Promise状态确定后,才会被加入队列
第一个代码执行顺序拆解
你给出的第一段代码执行步骤完全符合上述规则:
Promise.resolve() .then(() => { Promise.resolve().then(() => { Promise.resolve().then(() => { Promise.resolve().then(() => { console.log('first mega inner then') }) console.log('first very inner then') }) console.log('first inner then') }) console.log('first then') }) .then(() => { Promise.resolve().then(() => { Promise.resolve().then(() => { console.log('second very inner then') }) console.log('second inner then') }) console.log('second then') })
具体执行流程:
- 同步代码阶段:最外层
Promise.resolve()状态已完成,将第一个then的回调记为T1加入微任务队列。外层第二个then的回调记为T2,因前一个then返回的Promise还未resolve,暂不加入队列。此时微任务队列:[T1] - 同步栈清空,开始执行微任务队列:
- 执行
T1:内部创建的Promise的then回调T1_inner1加入微任务队列,打印first then。T1执行完毕,前一个then返回的Promise变为resolved,将T2追加到微任务队列末尾。此时微任务队列:[T1_inner1, T2] - 执行
T1_inner1:内部创建的Promise的then回调T1_inner2加入队列,打印first inner then。此时微任务队列:[T2, T1_inner2] - 执行
T2:内部创建的Promise的then回调T2_inner1加入队列,打印second then。此时微任务队列:[T1_inner2, T2_inner1] - 执行
T1_inner2:内部创建的Promise的then回调T1_inner3加入队列,打印first very inner then。此时微任务队列:[T2_inner1, T1_inner3] - 执行
T2_inner1:内部创建的Promise的then回调T2_inner2加入队列,打印second inner then。此时微任务队列:[T1_inner3, T2_inner2] - 执行
T1_inner3:打印first mega inner then。此时微任务队列:[T2_inner2] - 执行
T2_inner2:打印second very inner then
- 执行
你之前的预期错误核心是忽略了:第一个外层then回调执行完毕后,外层第二个then的回调会立刻被加入微任务队列,排在T1_inner2之前,所以会先执行T2输出second then,而非等所有内层嵌套的Promise回调执行完再处理外层链式的then。
新增queueMicrotask后的执行逻辑
你新增的queueMicrotask是在同步代码阶段执行的,不是在某个then回调内部执行的,所以执行步骤会发生变化:
- 同步代码阶段:
T1加入微任务队列后,立刻执行queueMicrotask(() => console.log('microtask')),将这个微任务记为QM追加到队列末尾。此时微任务队列:[T1, QM],T2还是暂未加入队列。 - 同步栈清空,开始执行微任务队列:
- 执行
T1:T1_inner1加入队列,打印first then,T1执行完毕,将T2追加到队列末尾。此时微任务队列:[QM, T1_inner1, T2] - 执行
QM:打印microtask。此时微任务队列:[T1_inner1, T2] - 后续执行逻辑和第一个场景完全一致,所以最终输出顺序和你看到的结果相同。
- 执行
内容的提问来源于stack exchange,提问作者Rasul
相关产品推荐
相关产品推荐

