文章中英模式
布魯斯前端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)
})
}
})
}
}