想要深入掌握 Promise 的运行机制,就必须先剖析其底层的状态机模型。核心原理其实就六个字:单向、不可逆、不可回退。理解 Promise 的关键,全在于这套状态变化的规则体系。

每一个 Promise 实例从创建的那一刻起,就处于三种状态之一:pending(待定)、fulfilled(已成功)、rejected(已失败)。状态的转换由执行器(executor)中显式调用的 resolve 或 reject 函数触发。一旦状态确定,便永久锁定,无法再更改。
状态只有三种,且严格单向转移
每个 Promise 实例在任何时刻都只属于以下一种状态:
- pending:初始阶段,既未成功也未失败,允许状态转变
- fulfilled:成功态,由
resolve(value)触发,之后状态固化,不可再变 - rejected:失败态,由
reject(reason)触发,同样永久锁定
状态之间的变更路径只有两条:pending → fulfilled 或 pending → rejected。一旦进入已完成或已拒绝状态,后续再调用 resolve 或 reject 都会被忽略。这就是“单向不可逆”的直观体现。
状态变更的原子性保障
每次调用 resolve 或 reject 时,内部会先检查当前状态是否仍为 pending:
- 如果不是
pending,直接返回,不执行任何操作 - 如果是
pending,才更新this.state,并保存this.value或this.reason
这种“先判断后修改”的原子性逻辑,确保了状态变更不会被重复或覆盖,竞态条件自然不复存在。换句话说,最先调用的 resolve 或 reject 决定了最终结果,后续调用都只能作为旁观者。
状态改变后触发对应回调
Promise 内部维护了两个回调队列:onFulfilledCallbacks 和 onRejectedCallbacks。当 then 被调用时,这些回调函数会被收集起来,等到状态真正变更后统一执行:
- 状态变为
fulfilled→ 遍历并执行所有成功回调,传入this.value - 状态变为
rejected→ 遍历并执行所有失败回调,传入this.reason
这里有一个关键的实现细节:这些回调通过 queueMicrotask(微任务)进行调度。它们会在当前同步代码执行完毕后、下一个宏任务开始之前被执行。这正是 Promise 实现“异步但不延迟”的底层机制——你注册的回调不会立即执行,但也不会被推迟到遥远的定时器里。
执行器立即运行,状态即刻可控
当 new Promise 时,传入的 executor 函数会同步立即执行。这意味着,resolve 或 reject 的调用时机完全由你掌控:
- 可以立刻 resolve,创建一个已成功的 Promise
- 可以在 setTimeout 后 reject,模拟异步失败场景
- 也可以直接抛出异常,自动触发 reject
这种设计让 Promise 的状态起点非常清晰,整个过程完全可预测。正是基于这套稳固的状态机模型,链式调用和错误冒泡才能顺畅地运行起来。
