使用 TypeScript 实现一个 Promise

引言

Promise 是 JavaScript 中很常用的一个异步编程解决方案,它解决了回调地狱的问题,可以更加优雅地处理异步操作。在 TypeScript 中,我们也常常会使用 Promise 来处理异步请求。在本文中,我们将使用 TypeScript 来实现一个 Promise,以了解 Promise 的实现原理和带来更丰富的使用场景。

Promise 的基本原理

Promise 有三个状态:pendingfulfilledrejected,分别代表异步操作的进行中、已成功完成和已失败完成。一个 Promise 初始状态为 pending,当异步操作成功后,状态变为 fulfilled,并携带一个返回值;当异步操作失败后,状态变为 rejected,并携带一个错误原因。

我们可以使用 then 方法来注册 Promise 状态的回调函数,当异步操作成功后,执行 onFulfilled 回调函数,当异步操作失败后,执行 onRejected 回调函数。如果我们在使用 then 方法时,Promise 的状态尚未确定,则当前的 then 方法会先被放入 “待处理” 队列中,等到 Promise 状态确定后再执行。

TypeScript 实现一个 Promise

1. 定义一个 Promise 类

我们可以从最简单的形式开始定义一个 Promise 类,首先我们定义三个状态和两个回调函数。

type PromiseStatus = "pending" | "fulfilled" | "rejected"

class Promise {
  status: PromiseStatus
  result?: any
  errReason?: any

  onFulfilled: (result: any) => void
  onRejected: (reason: any) => void
  
  constructor(executor: (resolve: (result: any) => void, reject: (reason: any) => void) => void) {
    this.status = "pending"

    this.onFulfilled = (_: any) => { }
    this.onRejected = (_: any) => { }

    executor(this.resolve.bind(this), this.reject.bind(this))
  }
  
  // 省略 resolve 和 reject 方法
}

在定义类时,我们需要定义类的类型(type)和类的属性和方法。我们使用 type 定义了 PromiseStatus 类型,表示 Promise 的三种状态,也方便后续代码调用。

定义 Promise 类,它有三个属性:

  • status:表示 Promise 的状态,初始化为 pending
  • result:表示异步操作返回的结果,如果没有结果,则为 undefined
  • errReason:表示异步操作失败的原因。

另外,定义了两个回调函数:

  • onFulfilled:表示异步操作成功后的回调函数。
  • onRejected:表示异步操作失败后的回调函数。

Promise 类的构造函数中,我们需要传入一个参数 executor,这个函数会传入两个函数参数:resolvereject。当异步操作成功时,调用 resolve(result) 方法;当异步操作失败时,调用 reject(reason) 方法。

2. 实现 resolve 方法

当我们使用 resolve(result) 方法时,Promise 的状态应该从 pending 变为 fulfilled,并执行 onFulfilled(result) 回调函数。如果我们在 resolve(result) 方法之前调用了 then(onFulfilled) 方法,则会将 onFulfilled 方法加入待处理队列中。

resolve(result: any) {
  if (this.status !== "pending") {
    return
  }
  
  this.status = "fulfilled"
  this.result = result

  setTimeout(() => {
    while (this.onFulfilledQueue.length > 0) {
      this.onFulfilledQueue.shift()(this.result)
    }
  })
}

我们需要判断 Promise 的当前状态是否为 pending,如果不是,则不执行后续逻辑。如果当前状态为 pending,则修改状态为 fulfilled,并设置返回结果为 result。最后使用 setTimeout 来异步处理回调函数队列,以实现在异步执行完成后再执行回调函数。

3. 实现 reject 方法

resolve(result) 方法类似,当我们使用 reject(reason) 方法时,Promise 的状态应该从 pending 变为 rejected,并执行 onRejected(reason) 回调函数。如果我们在 reject(reason) 方法之前调用了 then(null, onRejected) 方法,则会将 onRejected 方法加入待处理队列中。

reject(reason: any) {
  if (this.status !== "pending") {
    return
  }
  
  this.status = "rejected"
  this.errReason = reason

  setTimeout(() => {
    while (this.onRejectedQueue.length > 0) {
      this.onRejectedQueue.shift()(this.errReason)
    }
  })
}

我们同样需要判断当前状态是否为 pending,并将状态修改为 rejected。最后异步处理回调函数队列。

4. 实现 then 方法

then(onFulfilled, onRejected) 方法是 Promise 中最基本的方法,我们可以使用它来注册 onFulfilledonRejected 两个回调函数。onFulfilled 函数和 onRejected 函数都是可选的,如果不需要,则使用 nullundefined 表示。

onFulfilledQueue: ((result: any) => void)[] = []
onRejectedQueue: ((reason: any) => void)[] = []

then(onFulfilled?: (result: any) => void, onRejected?: (reason: any) => void): Promise {
  const promise = new Promise(() => {})
  promise.onFulfilled = onFulfilled || promise.onFulfilled
  promise.onRejected = onRejected || promise.onRejected

  if (this.status === "pending") {
    this.onFulfilledQueue.push(promise.onFulfilled)
    this.onRejectedQueue.push(promise.onRejected)
  } else if (this.status === "fulfilled") {
    setTimeout(() => {
      promise.onFulfilled(this.result)
    })
  } else {
    setTimeout(() => {
      promise.onRejected(this.errReason)
    })
  }

  return promise
}

在 then 方法中,我们需要新建一个 Promise 对象,并将 onFulfilledonRejected 方法赋值。接着,判断当前 Promise 对象的状态分三种情况进行处理:

  • 当前状态为 pending 时,将 onFulfilledonRejected 方法放入待处理队列中,并返回新创建的 Promise 对象。
  • 当前状态为 fulfilled 时,直接执行 onFulfilled 方法,并返回新创建的 Promise 对象。
  • 当前状态为 rejected 时,直接执行 onRejected 方法,并返回新创建的 Promise 对象。

使用 TypeScript 实现一个 Promise 示例

我们可以使用上面实现的 Promise 类,来创建一个简单的例子。

// 定义一个异步方法
function fetchData(): Promise<string> {
  return new Promise((resolve: (result: string) => void, reject: (reason: any) => void) => {
    setTimeout(() => {
      resolve("Hello World!")
    }, 1000)
  })
}

// 使用异步方法
fetchData()
  .then((result) => {
    console.log("result:", result)
  })

在上述例子中,我们定义了一个异步方法 fetchData(),它返回一个 Promise 对象,并在 1 秒后调用 resolve("Hello World!") 方法来执行异步操作。最后我们通过 then 方法来获取 fetchData() 方法的返回值。

总结

在本文中,我们从 Promise 的基本原理开始讲解,然后使用 TypeScript 实现了一个 Promise 示例。使用 TypeScript 来实现 Promise 可以让我们更好的了解 Promise 的实现原理,并带来更丰富的使用场景。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/659e4702add4f0e0ff74ab85


纠错反馈