You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Promise构造器中resolve在setTimeout内的事件循环工作机制解惑

问题解答

一、澄清你对Promise .then() 回调入队时机的误解

你核心的误区在于:.then() 的回调不会在调用 .then() 时直接进入微任务队列。实际逻辑是:

  • 当调用 .then() 时,如果Promise处于 pending 状态,回调会被暂存在Promise实例的回调列表中,不会立刻入队。
  • 只有当Promise的状态变为 fulfilled 或 rejected 时,对应的暂存回调才会被推入微任务队列等待执行。

对应到你代码里的第一个Promise:

  1. 同步执行构造器时,setTimeout(() => resolve(3), 0) 只是把一个宏任务(定时器回调)扔进了宏任务队列,此时Promise还是 pending 状态。
  2. 调用 .then() 时,因为Promise是pending,所以这个 (val) => console.log(val) 回调被暂存起来,并没有进入微任务队列。
  3. 直到后续事件循环处理到定时器宏任务时,执行 resolve(3),把Promise状态改为 fulfilled,这时候才会把之前暂存的 .then() 回调推入微任务队列。
  4. 所以当这个回调执行时,Promise已经有了resolved的值3,自然能打印出来。

二、完整代码执行流程拆解

我们一步步走一遍代码的执行顺序:

  1. 同步代码阶段:
    • 执行第一个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,回调被推入微任务队列。
  2. 同步代码执行完毕,处理微任务队列:
    • 微任务队列里只有第二个Promise的 .then() 回调,执行它,打印 4。微任务队列清空。
  3. 处理宏任务队列:
    • 取出定时器回调执行:调用 resolve(3),将第一个Promise改为fulfilled状态,同时把之前暂存的 .then() 回调推入微任务队列。
  4. 宏任务执行完毕,再次处理微任务队列:
    • 执行第一个Promise的 .then() 回调,打印 3。

三、Node.js 微任务队列工作机制

Node.js的事件循环分为多个阶段(timers、pending callbacks、poll、check、close callbacks等),每个阶段处理对应的宏任务。而微任务队列的处理规则是:

  • 微任务分为两个队列,优先级从高到低:
    1. process.nextTick() 队列:所有通过 process.nextTick() 添加的任务优先执行。
    2. Promise微任务队列:包括 .then()/.catch()/.finally() 的回调,以及 queueMicrotask() 添加的任务。
  • 每个宏任务阶段执行完毕后,会先清空所有微任务队列:先把 process.nextTick 队列的所有任务执行完,再执行Promise微任务队列的所有任务,全部执行完后才会进入下一个宏任务阶段。
  • 注意:如果在微任务执行过程中又添加了新的微任务,这些新任务也会在当前微任务处理阶段被执行,直到微任务队列彻底清空。

内容的提问来源于stack exchange,提问作者lewislin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:57:48