要手动实现一个既符合 Promise A+ 规范、又支持微任务调度优先级的基础 Promise,需要同时完成两件事:严格遵循三态不可逆、then 链返回新 Promise、值穿透与错误冒泡;同时将回调通过可插拔的调度器(比如 queueMicrotask 或 Promise.resolve().th
要手动实现一个既符合 Promise A+ 规范、又支持微任务调度优先级的基础 Promise,需要同时完成两件事:严格遵循三态不可逆、then 链返回新 Promise、值穿透与错误冒泡;同时将回调通过可插拔的调度器(比如 queueMicrotask 或 Promise.resolve().then)异步执行。下面一步步拆解实现过程。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
实现这样一个 Promise,核心攻坚在于两个方面:首先是严格按照 Promise A+ 规范管理状态流转、then 链行为和值穿透逻辑;其次是把 resolve/reject 后的回调以可控优先级的微任务来触发——比如用 queueMicrotask、Promise.resolve().then,甚至一个可插拔的调度器,而不是直接同步调用或退化成宏任务。
Promise 实例必须维护 [[PromiseState]](pending/fulfilled/rejected)和 [[PromiseResult]](值或原因),状态只能从 pending 变成 fulfilled 或 rejected,一旦定型就不可逆转。构造函数接收执行器(executor),立即同步执行,同时向外暴露 resolve 和 reject。
try/catch 里包裹——如果执行过程中抛出异常,等价于调用 reject(e)。resolve 和 reject 都是“一次性”的函数,重复调用会被忽略,靠内部标志位来控制。[[PromiseResult]] 或再次触发状态变更。这些看似简单,但很多实现翻车就翻在不可逆性上。
then(onFulfilled, onRejected) 必须返回一个新 Promise——这是链式调用的基础。之后按照 A+ 的 Promise Resolution Procedure 去解析返回值。关键点如下:
onFulfilled 或 onRejected 返回了一个值 x,就递归调用 resolvePromise(promise2, x, resolve2, reject2) 来处理,包括 thenable 和循环引用等情况。promise2 就要被 reject,从而实现错误冒泡。this.onFulfilledCbs 这样的队列里);如果已经 settled 了,那就延迟调度这些回调,具体怎么延迟看下一节。A+ 规范其实没有规定具体的微任务实现,只要求回调必须异步执行。标准实现通常用 Promise.resolve().then 或 queueMicrotask。要支持优先级,可以抽象出一个调度器接口:
queueMicrotask(cb),这算是最高优先级的微任务。high 用 queueMicrotask、normal 用 Promise.resolve().then、low 用 setTimeout(cb, 0)(不过 setTimeout 实际上是宏任务,只是拿来对比示意,不推荐真这么干)。resolve/reject 内部,以及 then 中缓存回调被触发时,都统一走这个调度器:scheduler(() => { /* 执行所有 pending 回调 */ })。这样一来,优先级的影响就只体现在回调执行时机的相对顺序上,而不会改变 Promise 本身的语义。
除了上述核心逻辑,还有一些边界情况必须处理得滴水不漏:
promise.then(null, onRejected) 等价于 promise.catch(onRejected),能捕获上游错误。onFulfilled 抛错,下游的 catch 要能接到——这就是错误冒泡。then() 必须做值穿透:直接把值传下去或把错误扔下去。x 时要防止无限递归——如果 x === promise,直接 reject 一个 TypeError。其实微任务优先级这件事本身并不复杂,容易忽略的是它并不会改变 Promise A+ 的语义。优先级只影响回调的执行顺序——比如多个 queueMicrotask 总是会在 Promise.then 之前被清空。真正需要手动实现的,是把规范里那句“must be queued as a job”用可配置、可替换的调度策略落地。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述