promise状态原子性更新靠状态机+闭包+首次调用生效机制实现:初始pending,仅允许pending→fulfilled或pending→rejected单向变更,后续resolve/reject静默忽略,闭包内条件判断确保状态变更不可分割。

Promise 状态的原子性更新,不是靠加锁或时间戳比对实现的,而是通过状态机设计 + 闭包封装 + 首次调用生效机制三位一体完成的。
Promise 状态只能变一次,这是硬约束
- 初始状态永远是
pending - 只能从
pending → fulfilled或pending → rejected,不可逆 - 一旦进入
fulfilled或rejected,后续所有resolve()或reject()调用都被静默忽略
这个“只能变一次”的行为,是 Promise/A+ 规范强制要求的,也是原子性的根本来源。
实现关键:闭包私有状态 + 条件判断
手写一个极简版就能看清逻辑:
function MyPromise(executor) {
let state = 'pending';
let value = undefined;
let reason = undefined;
function resolve(val) {
if (state === 'pending') {
state = 'fulfilled';
value = val;
}
// 后续调用直接跳过,不报错也不生效
}
function reject(err) {
if (state === 'pending') {
state = 'rejected';
reason = err;
}
}
executor(resolve, reject);
}
-
state、value、reason被封闭在构造函数作用域内,外部无法直接修改 -
resolve和reject内部都先判断state === 'pending',只在符合条件时才赋值 - 这个判断就是原子性的“闸门”,确保状态变更动作要么完整执行,要么完全跳过
不依赖外部同步机制,天然线程安全
- 没有用
Mutex、flag、Date.now()或AbortController - 即使并发调用多个
resolve('a')、resolve('b'),也只会有一个生效 - 在浏览器或 Node.js 的单线程事件循环下,这个判断和赋值是不可分割的操作(microtask 内部执行,无抢占)
注意:原子性 ≠ 所有操作都成功
resolve()调用本身是原子的,但它的参数可能来自异步计算、网络响应等——那些过程不在此保障范围内原子性只管“状态改没改”,不管“值对不对”或“有没有副作用”
所以业务中仍需校验
response.ok、手动抛错、统一错误处理,不能把责任全推给 Promise 机制状态变更前必须严格检查当前是否为
pendingresolve/reject函数应仅作为状态终结入口,不承担业务逻辑避免在
then回调里重复调用resolve,那已脱离原子控制范围











