魯斯前端布魯斯前端

文章中英模式

布魯斯前端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)
        })
      }
    })
  }
}