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