引言
Promise 是 JavaScript 中很常用的一个异步编程解决方案,它解决了回调地狱的问题,可以更加优雅地处理异步操作。在 TypeScript 中,我们也常常会使用 Promise 来处理异步请求。在本文中,我们将使用 TypeScript 来实现一个 Promise,以了解 Promise 的实现原理和带来更丰富的使用场景。
Promise 的基本原理
Promise 有三个状态:pending
,fulfilled
和 rejected
,分别代表异步操作的进行中、已成功完成和已失败完成。一个 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
,这个函数会传入两个函数参数:resolve
和 reject
。当异步操作成功时,调用 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 中最基本的方法,我们可以使用它来注册 onFulfilled
和 onRejected
两个回调函数。onFulfilled
函数和 onRejected
函数都是可选的,如果不需要,则使用 null
和 undefined
表示。
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 对象,并将 onFulfilled
和 onRejected
方法赋值。接着,判断当前 Promise 对象的状态分三种情况进行处理:
- 当前状态为
pending
时,将onFulfilled
和onRejected
方法放入待处理队列中,并返回新创建的 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