标准答案
- 状态机:Promise 至少有 pending、fulfilled、rejected 三种状态。状态只能从 pending 变为 fulfilled 或 rejected,一旦确定就不可逆。
- executor:new Promise 时 executor 会立即同步执行。resolve 用来把状态变为 fulfilled,reject 用来变为 rejected;executor 内部抛错时也应该进入 rejected。
- 回调队列:如果 then 调用时 Promise 仍是 pending,需要把成功回调和失败回调分别存入队列;等状态确定后,再异步执行对应队列。
- 链式调用:then 必须返回一个新的 Promise。回调返回普通值,新 Promise fulfilled;回调抛错,新 Promise rejected;回调返回 Promise 或 thenable,新 Promise 要等待它的最终状态。
题目解析
基础实现不必完整通过 Promise/A+,但要讲清状态不可逆、回调队列、then 返回新 Promise。
then 返回新 Promise 是链式调用的核心。如果 then 直接返回 this,后续链路的值传递、错误穿透和状态隔离都会出问题。
Promise 回调不是同步立刻执行,而是通过微任务调度。手写时可以用 queueMicrotask 模拟,理解上要和 setTimeout 这种宏任务区分开。
完整实现还要处理 thenable 吸收、循环引用保护、同一个 Promise 多次 then、错误穿透和值穿透。核心版可以先覆盖状态机和链式调用,再逐步补边界。
代码示例
下面是核心版实现,重点展示状态不可逆、回调队列和 then 返回新 Promise。
JavaScript
class MyPromise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.handlers = []
const resolve = (value) => this.settle('fulfilled', value)
const reject = (reason) => this.settle('rejected', reason)
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
settle(state, value) {
if (this.state !== 'pending') return
this.state = state
this.value = value
this.handlers.forEach(handler => this.run(handler))
this.handlers = []
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const handler = { onFulfilled, onRejected, resolve, reject }
if (this.state === 'pending') {
this.handlers.push(handler)
} else {
this.run(handler)
}
})
}
run(handler) {
queueMicrotask(() => {
const callback = this.state === 'fulfilled'
? handler.onFulfilled
: handler.onRejected
if (typeof callback !== 'function') {
const next = this.state === 'fulfilled' ? handler.resolve : handler.reject
next(this.value)
return
}
try {
handler.resolve(callback(this.value))
} catch (error) {
handler.reject(error)
}
})
}
}常见误区
- then 直接返回 this,导致链式调用状态混乱。
- 忘记 pending 状态下要收集多个回调。
- 没有处理回调抛错和返回 Promise 的情况。