文章中英模式
布鲁斯前端JS面试题目 - 手写 Promise 实现
学习如何从零手写实现 JavaScript Promise,理解异步处理原理,掌握 Promise A+ 规范,提升前端面试竞争力。
文章中英模式
懒得看文章?那就来看视频吧
Promise 概述
Promise 是 JavaScript 中处理异步操作的标准方式,它代表一个尚未完成但最终会完成的操作。在面试中,手写 Promise 实现是检验对异步处理、事件循环和 Promise A+ 规范理解的常见题目。
Promise 的三种状态
- 1.
pending
:初始状态,既不是成功也不是失败 - 2.
fulfilled
:操作成功完成,带有一个结果值 - 3.
rejected
:操作失败,带有一个错误原因
Promise 状态转换只能是:
- 1. pending → fulfilled
- 2. pending → rejected
一旦 Promise 状态变更,就不能再次变更。这种特性称为「不可变性」。
基本版 Promise 实现
以下是一个简化版的 Promise 实现,包含基本功能:
class MyPromise {
constructor(executor) {
this.state = 'pending' // 初始状态
this.value = undefined // 成功时的值
this.reason = undefined // 失败时的原因
this.onFulfilledCbs = [] // 存储成功回调函数数组
this.onRejectedCbs = [] // 存储失败回调函数数组
// 成功处理函数
const resolve = (value) => {
if (this.state === 'pending') {
queueMicrotask(() => { // 确保异步执行
this.state = 'fulfilled'
this.value = value
this.onFulfilledCbs.forEach(fn => fn()) // 执行所有注册的成功回调
})
}
}
// 失败处理函数
const reject = (reason) => {
if (this.state === 'pending') {
queueMicrotask(() => { // 确保异步执行
this.state = 'rejected'
this.reason = reason
this.onRejectedCbs.forEach(fn => fn()) // 执行所有注册的失败回调
})
}
}
// 立即执行传入的函数,捕获可能的错误
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
// 链式调用核心方法
then(onFulfilled, onRejected) {
// 参数处理,确保 onFulfilled 和 onRejected 是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }
// 返回新的 Promise 实现链式调用
return new MyPromise((resolve, reject) => {
// 统一处理回调逻辑
const handle = (callback, val, resolver, rejecter) => {
queueMicrotask(() => {
try {
const result = callback(val)
// 处理回调返回 Promise 的情况
result instanceof MyPromise
? result.then(resolver, rejecter)
: resolver(result)
} catch (err) {
rejecter(err)
}
})
}
// 根据当前 Promise 状态决定如何处理
if (this.state === 'fulfilled') {
handle(onFulfilled, this.value, resolve, reject)
} else if (this.state === 'rejected') {
handle(onRejected, this.reason, resolve, reject)
} else {
// Promise 还在 pending 状态,将回调存入对应数组
this.onFulfilledCbs.push(() => {
handle(onFulfilled, this.value, resolve, reject)
})
this.onRejectedCbs.push(() => {
handle(onRejected, this.reason, resolve, reject)
})
}
})
}
}