Promise 构造器必须同步执行 executor,但 resolve/reject 不立即触发 then 回调;所有 onFulfilled/onRejected 必须异步且走微任务;then 必须返回新 Promise 并遵循 Promise Resolution Procedure;状态常量应统一定义,实例属性需在 constructor 中明确初始化。

Promise 构造器必须同步执行 executor,但 resolve/reject 不代表立即触发 then 回调
很多人误以为 resolve(value) 一调用,then 里的回调就立刻执行——这是错的。Promises/A+ 明确要求:所有 onFulfilled 和 onRejected 必须异步调用,且必须走微任务(microtask),不能是宏任务(如 setTimeout)。
实操要点:
- 构造函数内必须立即
try { executor(resolve, reject) } catch (e) { reject(e) } -
resolve和reject函数内部只负责更新状态(this.status)和保存值(this.value或this.reason),**不直接执行回调** - 真正执行注册的回调,要靠
queueMicrotask(() => { /* 遍历并调用 onFulfilledCallbacks */ }) - 若环境不支持
queueMicrotask(如 Node.js Promise.resolve().then(fn) 模拟;绝不能用setTimeout(fn, 0),它会把回调推到下一轮事件循环,违反规范
三态不可逆 + 状态检查必须嵌入 resolve/reject 内部
Promise 的 PENDING → FULFILLED 和 PENDING → REJECTED 是单向的,一旦状态变更,后续任何 resolve 或 reject 调用都应被忽略。这个“忽略”不是靠外部逻辑控制,而是必须在 resolve/reject 函数体第一行做判断。
常见错误现象:
- 没加状态守卫,导致多次
resolve把this.value覆盖,或触发重复回调 - 把状态判断放在
then注册时,而不是在resolve执行时——这无法阻止 executor 内部多次调用resolve(1); resolve(2);
正确写法示例片段:
function resolve(value) {
if (self.status !== PENDING) return; // 关键守卫
self.status = FULFILLED;
self.value = value;
queueMicrotask(() => {
self.onFulfilledCallbacks.forEach(cb => cb(value));
});
}
then 必须返回新 Promise,且返回值处理依赖 resolvePromise 辅助函数
promise.then(onFulfilled, onRejected) 每次调用都必须返回一个全新 Promise 实例,它的终态由回调函数的返回值 x 决定——这不是简单赋值,而是一套递归展开规则(即 Promises/A+ 的 “Promise Resolution Procedure”)。
容易踩的坑:
- 直接
return new MyPromise(...)但没处理x类型:比如x是另一个MyPromise实例、是 thenable 对象、甚至是undefined或循环引用(x === promise2) - 没用
try/catch包裹onFulfilled执行,导致抛错后新 Promise 没被reject,错误静默丢失 - 把
resolvePromise写成普通工具函数却忘了传入新 Promise 的resolve/reject引用,造成闭包丢失
关键参数签名必须是:resolvePromise(promise2, x, resolve, reject),其中 promise2 是 then 返回的那个新实例。
静态状态常量定义与实例属性初始化要分离
状态字面量('pending'、'fulfilled')建议用类静态属性或模块级常量,而非硬编码字符串——既防拼写错误,也利于后期扩展(如加 MyPromise.STATUS 命名空间)。
但注意:实例自身的 this.status、this.value、this.reason、this.onFulfilledCallbacks 等,必须在 constructor 中初始化,且初始值要明确:
-
this.status = MyPromise.PENDING(不能是undefined或空字符串) -
this.value = undefined(即使成功值为0或false,也要区分“未设置”和“设为 falsy 值”) -
this.onFulfilledCallbacks = [](空数组,不是null或undefined,否则push会报错)
最易被忽略的细节是:onFulfilledCallbacks 和 onRejectedCallbacks 这两个队列,在 status 变更为非 PENDING 后,必须清空或重置为新数组——否则下次再调用 then,旧回调可能被重复执行。

















