从零手写一个符合规范的 Promise
从零手写一个符合规范的 Promise
会用 Promise 之后,想真正理解它只能手写一遍。核心结构:构造函数接收执行器,状态只能从 pending → fulfilled/rejected 单向流转。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.state = PENDING
this.value = undefined
this.callbacks = [] // then 在 pending 时先存起来
const resolve = (value) => {
if (this.state !== PENDING) return
this.state = FULFILLED
this.value = value
this.callbacks.forEach((cb) => cb.onFulfilled(value))
}
const reject = (reason) => {
if (this.state !== PENDING) return
this.state = REJECTED
this.value = reason
this.callbacks.forEach((cb) => cb.onRejected(reason))
}
executor(resolve, reject)
}
then 的链式调用
then 必须返回一个新 Promise,这是链式调用的关键:
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const handle = (fn) => {
queueMicrotask(() => {
try {
const x = fn(this.value)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) { reject(e) }
})
}
if (this.state === FULFILLED) handle(onFulfilled)
else if (this.state === REJECTED) handle(onRejected)
else this.callbacks.push({
onFulfilled: () => handle(onFulfilled),
onRejected: () => handle(onRejected),
})
})
}
几个要点:
- 回调必须包在
queueMicrotask里——Promise 回调永远是微任务,即使 Promise 已经 resolve - then 的回调返回值 x 如果是 thenable,要"解包"后再决定新 Promise 的状态
- 回调抛异常,新 Promise 要 reject,所以包 try/catch
衍生方法
catch(fn) 就是 then(null, fn);finally 不管成败都执行且透传原值;静态方法:
Promise.resolve:值包装,thenable 会同化Promise.all:全部成功才成功,一个失败立即失败Promise.allSettled:等全部落定,返回状态数组Promise.race:第一个落定的为准(可做超时控制)
写完建议跑一遍 promises-aplus-tests 测试套件,能过 872 个用例才算合格。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~