实现 Promise/A+ 规范
手写符合 Promises/A+ 规范的 Promise
问题
从零实现一个符合 Promises/A+ 规范的 Promise。
解答
完整实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
// 存储回调函数,处理异步情况
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
// 只有 pending 状态才能转换
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 执行所有失败回调
this.onRejectedCallbacks.forEach(fn => fn())
}
}
// 执行器可能抛出异常
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// 值穿透:参数不是函数时,创建默认函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
// then 返回新的 Promise
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledTask = () => {
// 使用 queueMicrotask 确保异步执行
queueMicrotask(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
const rejectedTask = () => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.status === FULFILLED) {
fulfilledTask()
} else if (this.status === REJECTED) {
rejectedTask()
} else {
// pending 状态,存储回调
this.onFulfilledCallbacks.push(fulfilledTask)
this.onRejectedCallbacks.push(rejectedTask)
}
})
return promise2
}
catch(onRejected) {
return this.then(null, onRejected)
}
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason })
)
}
static resolve(value) {
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason))
}
}
// 处理 then 返回值的各种情况
function resolvePromise(promise2, x, resolve, reject) {
// 不能返回自身,防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'))
}
// 防止多次调用
let called = false
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
const then = x.then
if (typeof then === 'function') {
// x 是 thenable 对象
then.call(
x,
y => {
if (called) return
called = true
// 递归解析,y 可能还是 Promise
resolvePromise(promise2, y, resolve, reject)
},
r => {
if (called) return
called = true
reject(r)
}
)
} else {
// 普通对象
resolve(x)
}
} catch (error) {
if (called) return
called = true
reject(error)
}
} else {
// x 是原始值
resolve(x)
}
}
测试用例
// 基本使用
new MyPromise((resolve) => {
setTimeout(() => resolve('success'), 100)
})
.then(value => {
console.log(value) // 'success'
return 'next'
})
.then(value => {
console.log(value) // 'next'
})
// 链式调用返回 Promise
MyPromise.resolve(1)
.then(v => new MyPromise(resolve => resolve(v + 1)))
.then(v => console.log(v)) // 2
// 值穿透
MyPromise.resolve('hello')
.then()
.then(v => console.log(v)) // 'hello'
// 错误处理
MyPromise.reject('error')
.catch(e => console.log(e)) // 'error'
关键点
- 三种状态:pending → fulfilled 或 pending → rejected,状态不可逆
- 异步执行:回调必须异步执行,使用
queueMicrotask或setTimeout - 值穿透:
then参数不是函数时,值会传递到下一个then - resolvePromise:处理返回值是 Promise、thenable、普通值的情况
- 防止循环引用:
then返回的 Promise 不能是自身
目录