promise构造函数必须同步执行executor且仅一次,then返回新promise并支持值穿透,回调需try/catch包裹,微任务调度须用queuemicrotask或promise.resolve().then(),resolve promise值时需防循环引用。

Promise 构造函数必须能接收执行器函数并立即同步调用
这是 Promises/A+ 最基础的约束:传入 new Promise(executor) 的 executor 必须在实例化时**同步执行**,且只执行一次。如果异步调用 resolve 或 reject(比如包一层 setTimeout),会导致状态不可变性失效或违反“pending → fulfilled/rejected”单向流转规则。
实操建议:
- 在构造函数内直接
try { executor(resolve, reject) } catch (e) { reject(e) },不加任何异步包装 -
resolve和reject是闭包捕获的内部函数,需绑定当前 promise 实例的状态和值 - 必须检查重复调用:一旦状态变为
fulfilled或rejected,后续所有resolve/reject调用必须被忽略
then 方法必须返回新 Promise 并支持链式调用与值穿透
then 不是修改原 Promise,而是返回一个全新的 Promise,其状态由回调函数的返回值或抛出错误决定。Promises/A+ 明确要求「值穿透」行为:当 onFulfilled 或 onRejected 未提供或不是函数时,要透传前一个 promise 的结果。
实操建议:
- 无论当前 promise 处于什么状态(pending/fulfilled/rejected),
then都必须返回新 promise 实例 - 对
onFulfilled和onRejected做类型判断:typeof fn === 'function',否则设为默认透传函数(如value => value和reason => { throw reason }) - 回调执行必须包裹在
try/catch中,异常必须被reject到新 promise,不能泄露到全局
微任务调度必须使用 queueMicrotask 或兼容降级方案
Promises/A+ 本身不规定调度机制,但规范隐含要求「then 回调必须在当前任务结束后、下一个宏任务开始前执行」,即微任务语义。浏览器中应优先用 queueMicrotask;Node.js 11+ 支持,旧版需 fallback 到 Promise.resolve().then();若环境完全无 Promise,则无法合规(因为 Promise 规范自身依赖微任务)。
实操建议:
- 定义统一的微任务调度函数:
const nextTick = typeof queueMicrotask === 'function' ? queueMicrotask : fn => Promise.resolve().then(fn) - 所有「状态变更后触发 then 回调」的逻辑(如 resolve 后遍历 pending 队列),必须通过
nextTick推入微任务队列 - 不要用
setTimeout(fn, 0)或setImmediate—— 它们是宏任务,会破坏 Promise.then 的执行时序,导致测试失败(如 Promises/A+ test suite 中的 `2.2.4` 条款)
处理 resolve Promise 值时必须递归展开并防止循环引用
当 resolve 传入的是另一个 Promise(或 thenable),必须「展平」它:获取其 then 方法并调用,把当前 promise 的 resolve/reject 作为参数传入,形成链式委托。关键难点在于检测并拒绝循环引用(例如 resolve(promise) 自身)。
实操建议:
- 在
resolve内部先判断x是否为当前 promise 实例(if (x === promise) { reject(new TypeError('Chaining cycle detected')) }) - 再判断
x是否为 object / function,且有可访问的then属性(注意属性访问可能抛错,需 try/catch) - 调用
x.then(y => resolve(y), r => reject(r))时,必须确保只调用一次(用called标志位),且该调用本身也必须走微任务(避免同步爆栈)
真正难的不是写完一个能跑的 Promise,而是让所有边界 case(如 resolve 一个带 getter 的 thenable、嵌套 100 层 then、同步 throw + 异步 resolve 混用)都通过 Promises/A+ 官方测试集。最易被忽略的是微任务调度的严格性——哪怕只有一处漏掉 nextTick,整个链式时序就崩了。










