promise构造函数需同步执行executor并用try/catch捕获异常后reject;then必须返回新promise并实现resolvepromise处理穿透;resolve/reject/all等需兼容thenable;状态不可逆且回调须微任务异步执行。

Promise 构造函数必须处理 executor 参数的同步抛错
规范要求,传入 new Promise(executor) 的 executor 函数会**立即同步执行**,且如果它抛出异常,必须以该异常为 reason 拒绝新 promise。很多手写实现漏掉这一层 try/catch,导致错误直接冒泡到全局,违反规范。
实操建议:
- 在构造函数内部立即调用
executor(resolve, reject) - 用
try...catch包裹整个调用,捕获同步异常后调用reject(error) - 注意:
resolve和reject是你手动实现的函数,需绑定当前 promise 实例(即this)
then 方法必须返回新 Promise 并支持链式调用
then 不得修改原 promise 状态,必须返回一个**全新的 promise**;且当传入的 onFulfilled 或 onRejected 返回值是 promise 时,要遵循「穿透」规则(即新 promise 的状态由该返回值决定)。
常见错误现象:
- 直接返回
this—— 导致状态污染和链式失效 - 忽略返回值是 promise 的情况,未做
resolve递归展开(即没实现 Promise Resolution Procedure) - 未处理
onFulfilled/onRejected抛错:此时应以该错误拒绝新 promise
关键点:你必须实现一个独立的 resolvePromise(promise2, x, resolve, reject) 辅助函数,专门处理各种 x 类型(undefined、普通值、thenable、自身 promise 循环引用等)。
静态方法 resolve/reject/all/race 必须兼容非 Promise 值
Promise.resolve(x) 不是简单地返回 new Promise(r => r(x))。规范要求它必须先判断 x 是否为 thenable(有 then 方法的对象/函数),若是,则“尝试”接纳其状态;否则才以 x 为 value 兑现。
使用场景与差异:
-
Promise.resolve(42)→ 立即 fulfilled 的 promise -
Promise.resolve(Promise.resolve(42))→ 等价于后者,不嵌套 -
Promise.resolve({ then: (r) => r(42) })→ 执行其then,结果由回调决定 -
Promise.all([1, Promise.resolve(2), Promise.reject('e')])→ 返回 rejected promise,reason 是'e',不是数组
容易踩的坑:直接对数组元素调用 Promise.resolve 而不等待全部完成,或在 all 中忽略空数组/非数组输入的边界处理。
状态机必须严格不可逆且仅触发一次回调
Promise/A+ 明确规定:状态只能从 pending → fulfilled 或 pending → rejected,且一旦改变,后续所有 then 调用都必须异步执行对应回调(即使 promise 已 settled)。这意味着你不能在 resolve 后再调用 reject,也不能多次触发同一个回调。
实操建议:
- 用私有属性(如
this._state = 'pending')记录状态,每次变更前加if (this._state !== 'pending') return - 回调队列(
this._onFulfilledQueue)必须在状态变更后统一异步清空(用queueMicrotask或Promise.resolve().then模拟微任务) - 不要用
setTimeout模拟 —— 它是宏任务,违反规范中「then 回调必须在本轮事件循环末尾执行」的要求
最易被忽略的是微任务调度的准确性:手写时若依赖宿主环境的 Promise 来调度(比如用 Promise.resolve().then),就形成循环依赖,无法真正脱离原生 Promise 运行 —— 这正是规范测试套件(promises-aplus-tests)会卡住的关键点。










