Promise必须严格实现三态单向流转、executor同步执行、then异步回调、返回新Promise、错误穿透及resolvePromise递归展开thenable等规范,且须通过promises-aplus-tests验证。

Promise 构造函数必须处理三种状态和同步/异步执行逻辑
Promise 实例初始化时必须支持 pending、fulfilled、rejected 三态,且状态只能单向流转(pending → fulfilled 或 pending → rejected),不可逆。构造函数接收的执行器(executor)必须**立即同步调用**,但其内部的 resolve / reject 回调可能触发异步行为——这意味着你不能简单地在 executor 里直接 return,而要靠队列或微任务调度后续的 then 回调。
实操建议:
- 用闭包变量(如
state、value、reason)保存当前状态与结果,初始为'pending' -
resolve和reject必须是函数,且需检查当前是否仍为pending状态,否则忽略调用(防止多次 resolve/reject) - 所有
then注册的回调必须通过queueMicrotask或Promise.resolve().then延迟执行,确保符合“onFulfilled/onRejected 必须异步调用”的规范要求 - 注意:Node.js 11+ 支持
queueMicrotask;若需兼容旧环境,可用Promise.resolve().then模拟,但不要用setTimeout(那是宏任务,违反规范)
then 方法必须返回新 Promise 并正确处理返回值类型
then 不是链式调用的语法糖,而是规范强制要求每次调用都返回一个**全新 Promise**,且该 Promise 的终态由 onFulfilled/onRejected 的返回值决定。这个“返回值处理逻辑”正是 Promises/A+ 测试套件(promises-aplus-tests)最密集校验的部分。
实操建议:
- 无论 onFulfilled/onRejected 是否抛错,只要它们被调用,就必须用
resolvePromise(promise2, x, resolve, reject)这个辅助函数统一处理返回值x -
x可能是普通值、undefined、null、另一个 Promise 实例、或带有then方法的类 Promise 对象(即“thenable”)——必须递归展开直到取到非 thenable 值 - 特别注意循环引用:当
x === promise2时,必须以TypeError拒绝 promise2(规范第 2.3.1 条) - 如果 onFulfilled/onRejected 抛出异常
e,则promise2必须以e拒绝(即reject(e))
拒绝处理与错误穿透必须靠 try/catch + 统一 reject 分发
规范明确要求:当 onFulfilled 或 onRejected 抛出异常,且当前 Promise 处于 fulfilled 或 rejected 状态时,该异常必须作为下一个 Promise 的 rejection reason 向下传递。这叫“错误穿透”,不是靠 catch 语法糖实现的,而是 then 内部对回调执行的严格包裹逻辑。
实操建议:
- 每个 onFulfilled/onRejected 调用都必须包裹在
try...catch中,捕获后立即调用reject(传给当前then返回的新 Promise) - 不要在
catch里重新 throw,也不要忽略错误——错误必须显式交由新 Promise 的reject处理 - 当 onRejected 未提供(即
then(onFulfilled, undefined)),应默认将前一个 rejection reason 透传给下一个 Promise,这是靠onRejected = onRejected || (r => { throw r })这类默认逻辑实现的 - 注意:规范不强制要求
catch方法存在,它是then(undefined, onRejected)的语法糖,可后期基于then补充实现
测试验证必须跑通 promises-aplus-tests 且禁用非标准扩展
手写 Promise 最容易自以为正确却在边界 case 上失败。Promises/A+ 规范本身没有“文档式解释”,只有测试用例定义行为。不跑测试,等于没实现。
实操建议:
- 安装官方测试工具:
npm install -g promises-aplus-tests,然后运行promises-aplus-tests path/to/your/promise.js - 你的入口文件(如
my-promise.js)必须导出一个符合规范的PromisesAPlusTest兼容接口:即exports.deferred = function() { ... },返回含promise、resolve、reject三属性的对象 - 禁止在实现中添加非规范方法(如
finally、allSettled、any),哪怕只加一行也会导致测试失败——这些是 ES2015+ 或 WHATWG 的扩展,不在 Promises/A+ 范围内 - 常见失败点:微任务调度不一致(尤其在 Node.js 与浏览器混测时)、
resolvePromise对then方法的调用未做防重入保护、对undefined或null的 thenable 判断漏判
真正卡住人的从来不是“怎么写 resolve”,而是 resolvePromise 函数里对 thenable 展开的 7 层嵌套条件判断,以及测试时发现某一个 case 总是 timeout 却查不出哪少了一次 queueMicrotask。规范文本只有一页,但每句话都对应一个必须死磕的执行路径。










