Skip to content

手写 Promise:实现符合 Promises/A+规范的 Promise

TIP

Promise是 JavaScript 中非常重要的一个概念,它是一种用于处理异步操作的编程模型。Promise提供了一种优雅的方式来处理异步操作的成功或失败,以及它们之间的依赖关系。这使得我们可以避免回调地狱(Callback Hell)的问题,编写更清晰、更易于理解的代码。

Promises/A+是一个对Promise行为的开放规范,它规定了Promise应该如何表现和实现。遵循这个规范的Promise实现可以确保它们之间的互操作性,使得我们可以在不同的库和框架中轻松地使用它们。在本文中,我们将实现一个名为myPromise的类,它将遵循Promises/A+规范。

我们将实现以下功能和方法,使 myPromise 符合 Promises/A+规范:

  1. myPromise 构造函数及基本状态
  2. resolve 和 reject 方法
  3. then方法
  4. catch方法
  5. finally方法
  6. 静态方法 resolve、reject、all、race等

完整代码

点击查看代码
ts
class myPromise<T> {
  status: 'pending' | 'fulfilled' | 'rejected'
  value: T | undefined
  reason: any
  onFulfilledCallbacks: Function[]
  onRejectedCallbacks: Function[]
  constructor(executor: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void) {
    // 初始化状态为pending
    this.status = 'pending'
    // 初始化成功的值为undefined
    this.value = undefined
    // 初始化失败的原因为undefined
    this.reason = undefined
    // 初始化成功处理函数队列
    this.onFulfilledCallbacks = []
    // 初始化失败处理函数队列
    this.onRejectedCallbacks = []

    // 定义resolve方法
    const resolve = (value: T | undefined) => {
      // 只有在pending状态才能更改状态和值
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        this.value = value
        // 执行所有成功处理函数
        this.onFulfilledCallbacks.forEach((callback) => callback())
      }
    }

    // 定义reject方法
    const reject = (reason: any) => {
      // 只有在pending状态才能更改状态和原因
      if (this.status === 'pending') {
        this.status = 'rejected'
        this.reason = reason
        // 执行所有失败处理函数
        this.onRejectedCallbacks.forEach((callback) => callback())
      }
    }

    // 立即执行执行器函数
    try {
      executor(resolve, reject)
    } catch (error) {
      // 如果执行器函数抛出异常,将Promise状态更改为rejected
      reject(error)
    }
  }
  then(
    onFulfilled?: (value: T | undefined) => T | void,
    onRejected?: (reason: any) => any
  ): myPromise<T> {
    // 如果不传处理函数,则使用默认处理函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }

    // 创建一个新的Promise实例,称为promise2
    const promise2 = new myPromise<T>((resolve, reject) => {
      if (this.status === 'fulfilled') {
        // 使用setTimeout保证异步调用
        setTimeout(() => {
          try {
            // 调用onFulfilled,并获取返回值
            const x = onFulfilled!(this.value)
            // 使用返回值x和新的Promise实例promise2来处理resolve和reject
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            // 如果处理函数抛出异常,则将promise2状态更改为rejected
            reject(error)
          }
        })
      } else if (this.status === 'rejected') {
        // 使用setTimeout保证异步调用
        setTimeout(() => {
          if (onRejected) {
            try {
              // 调用onRejected,并获取返回值
              const x = onRejected(this.reason)
              // 使用返回值x和新的Promise实例promise2来处理resolve和reject
              resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              // 如果处理函数抛出异常,则将promise2状态更改为rejected
              reject(error)
            }
          }
        })
      } else if (this.status === 'pending') {
        // 如果当前Promise状态仍为pending,将处理函数加入相应的队列中
        this.onFulfilledCallbacks.push(() => {
          // 使用setTimeout保证异步调用
          setTimeout(() => {
            try {
              // 调用onFulfilled,并获取返回值
              const x = onFulfilled!(this.value)
              // 使用返回值x和新的Promise实例promise2来处理resolve和reject
              resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              // 如果处理函数抛出异常,则将promise2状态更改为rejected
              reject(error)
            }
          })
        })

        this.onRejectedCallbacks.push(() => {
          // 使用setTimeout保证异步调用
          setTimeout(() => {
            if (onRejected) {
              try {
                // 调用onRejected,并获取返回值
                const x = onRejected(this.reason)
                // 使用返回值x和新的Promise实例promise2来处理resolve和reject
                resolvePromise(promise2, x, resolve, reject)
              } catch (error) {
                // 如果处理函数抛出异常,则将promise2状态更改为rejected
                reject(error)
              }
            }
          })
        })
      }
    })

    // 返回新的Promise实例,以便链式调用
    return promise2
  }
  catch(onRejected: (reason: any) => any) {
    // 调用then方法,仅传入失败处理函数
    return this.then(undefined, onRejected)
  }
  finally(callback: () => any) {
    // 调用then方法,传入两个相同的处理函数
    return this.then(
      (value) => {
        // 创建一个新的Promise实例,确保异步执行callback
        return myPromise.resolve(callback()).then(() => value)
      },
      (reason) => {
        // 创建一个新的Promise实例,确保异步执行callback
        return myPromise.resolve(callback()).then(() => {
          throw reason
        })
      }
    )
  }
  static resolve(value) {
    if (value instanceof myPromise) {
      return value
    }
    return new myPromise((resolve, _reject) => {
      resolve(value)
    })
  }

  static reject(reason) {
    return new myPromise((_resolve, reject) => {
      reject(reason)
    })
  }
  static all(promises) {
    return new myPromise((resolve, reject) => {
      const result = []
      let resolvedCount = 0

      promises.forEach((promise, index) => {
        myPromise.resolve(promise).then(
          (value) => {
            result[index] = value
            resolvedCount++
            if (resolvedCount === promises.length) {
              resolve(result)
            }
          },
          (reason) => {
            reject(reason)
          }
        )
      })
    })
  }

  static race(promises) {
    return new myPromise((resolve, reject) => {
      promises.forEach((promise) => {
        myPromise.resolve(promise).then(
          (value) => {
            resolve(value)
          },
          (reason) => {
            reject(reason)
          }
        )
      })
    })
  }
  static any(promises) {
    return new myPromise((resolve, reject) => {
      const errors = []
      let rejectedCount = 0

      promises.forEach((promise, index) => {
        myPromise.resolve(promise).then(
          (value) => {
            resolve(value)
          },
          (reason) => {
            errors[index] = reason
            rejectedCount++
            if (rejectedCount === promises.length) {
              reject(new AggregateError(errors, 'All promises were rejected'))
            }
          }
        )
      })
    })
  }
}

function resolvePromise<T>(
  promise2: myPromise<T>,
  x: any,
  resolve: (value?: any) => void,
  reject: (reason?: any) => void
) {
  // 1. 如果 promise2 和 x 相同,抛出 TypeError
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'))
  }

  // 标记是否已调用,防止多次调用
  let called = false

  // 2. 如果 x 是 myPromise 实例
  if (x instanceof myPromise) {
    // 根据 x 的状态调用 resolve 或 reject
    x.then(
      (y) => {
        resolvePromise(promise2, y, resolve, reject)
      },
      (reason) => {
        reject(reason)
      }
    )
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    // 3. 如果 x 是对象或函数
    try {
      // 获取 x 的 then 方法
      const then = x.then
      if (typeof then === 'function') {
        // 如果 then 是函数
        // 使用 x 作为上下文调用 then 方法
        then.call(
          x,
          (y) => {
            // 成功回调
            if (called) return // 如果已经调用过,直接返回
            called = true
            // 递归处理 y
            resolvePromise(promise2, y, resolve, reject)
          },
          (reason) => {
            // 失败回调
            if (called) return // 如果已经调用过,直接返回
            called = true
            reject(reason)
          }
        )
      } else {
        // 如果 then 不是函数
        // 直接调用 resolve
        resolve(x)
      }
    } catch (error) {
      // 如果获取或调用 then 方法抛出异常
      if (called) return // 如果已经调用过,直接返回
      called = true
      reject(error)
    }
  } else {
    // 4. 如果 x 不是对象或函数
    // 直接调用 resolve
    resolve(x)
  }
}

测试

ts
// 示例用法
const myCustomPromise = new myPromise<string>((resolve, reject) => {
  setTimeout(() => {
    resolve('Custom Promise Resolved')
  }, 2000)
})

myCustomPromise
  .then((value) => {
    console.log(value) // 输出: Custom Promise Resolved
  })
  .catch((error) => {
    console.error(error)
  })

如有转载或 CV 的请标注本站原文地址