编辑
2023-06-18
手写源码系列
00
请注意,本文编写于 400 天前,最后修改于 362 天前,其中某些信息可能已经过时。

目录

Promise 的基本概念
Promise 的源码实现
Promise的实现过程解析
使用手写Promise
结论

JavaScript 中,Promise 是一种用于处理异步操作的对象,它可以让异步代码更易于理解和管理。在本文中,我们将手写实现一个 Promise对象实现其resolverejectthencatch方法。

Promise 的基本概念

在介绍 Promise 的实现方法之前,让我们先回顾一下 Promise 的基本概念。 Promise 有三种状态:

  • Pending(进行中):初始状态,表示 Promise 实例正在进行中。
  • Fulfilled(已完成):表示异步操作已经完成,并且 Promise 实例已经获得了一个值。
  • Rejected(已失败):表示异步操作已经失败,并且 Promise 实例已经获得了一个失败原因。

Promise 实例从 Pending 状态转变为 Fulfilled 或者 Rejected 状态时,我们称之为 Promise 已经 settled(已敲定)。

Promise 的源码实现

我们将使用 ES6 的类来实现一个 PromisePromise 类需要具备以下功能:

  • 接受一个 executor 函数作为参数,该函数将在 Promise 实例创建时立即执行,并传递两个回调函数,即 resolvereject 函数。
  • executor 函数内部,我们需要处理异步操作,如果操作成功,则使用 resolve 函数返回结果;如果操作失败,则使用 reject 函数返回错误信息。
  • Promise 实例需要提供 then 方法,该方法接受两个回调函数,即 onFulfilledonRejected,分别在 Promise 转变为 Fulfilled 或者 Rejected 状态时执行。
  • 如果在 executor 函数执行过程中发生错误,Promise 实例应该转变为 Rejected 状态,并且使用 reject 函数返回错误信息。
  • Promise 实例可以链式调用 then 方法,每个 then 方法可以返回一个新的 Promise 实例,实现 Promise 链。
  • Promise 实例需要提供 catch 方法,用于捕获 promise 对象的拒绝状态rejected的回调函数,它同样支持链式调用。

下面是我们的 Promise 类的基本实现:

javascript
class Promise { static Pending = "Pending"; static Fulfilled = "Fulfilled"; static Rejected = "Rejected"; constructor(executor) { this.status = Promise.Pending; this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { reject(error); } } resolve(value) { if (this.status === Promise.Pending) { this.status = Promise.Fulfilled; this.value = value; this.onFulfilledCallbacks.forEach((callback) => { callback(this.value); }); } } reject(reason) { if (this.status === Promise.Pending) { this.status = Promise.Rejected; this.reason = reason; this.onRejectedCallbacks.forEach((callback) => { callback(this.reason); }); } } then(onFulfilled, onRejected) { return new Promise((resolve, reject) => { if (this.status === Promise.Fulfilled) { setTimeout(() => { try { const result = onFulfilled(this.value); resolve(result); } catch (error) { reject(error); } }); } if (this.status === Promise.Rejected) { setTimeout(() => { try { const result = onRejected(this.reason); resolve(result); } catch (error) { reject(error); } }); } if (this.status === Promise.Pending) { this.onFulfilledCallbacks.push((value) => { setTimeout(() => { try { const result = onFulfilled(value); resolve(result); } catch (error) { reject(error); } }); }); this.onRejectedCallbacks.push((reason) => { setTimeout(() => { try { const result = onRejected(reason); resolve(result); } catch (error) { reject(error); } }, 0); }); } }); } catch(onRejected) { return this.then(null, onRejected); } }

Promise的实现过程解析

我们先创建了一个 Promise 类,其中包含了 Promise 的基本属性和方法。在构造函数中,我们定义了 statusvaluereason 三个变量用于保存 Promise 的状态和值,以及 onFulfilledCallbacksonRejectedCallbacks 两个数组用于保存 then 方法中传入的回调函数。

在随后的 try-catch 语句中,我们调用了 executor 函数,并将之后实现的 resolvereject 函数传入,以便在异步操作完成后调。

需要注意的是,我们需要通过this.xxx.bind(this)的方法来传入resolvereject函数,否则在这两个函数内无法访问到当前类的任何东西,这是一个JavaScript中的this指向问题,你可以从resolvereject函数在实际应用中的调用过程来思考这个问题。

然后,我们实现了 resolvereject 两个函数,分别用于处理 PromiseFulfilledRejected 状态。

接下来,我们实现了 then 函数。当 Promise 的状态为 Fulfilled 时,我们使用 setTimeout 函数将 onFulfilled 回调函数放入微任务队列中,以确保在本轮事件循环结束后执行。同样的,当 Promise 的状态为 Rejected 时,我们使用 setTimeout 函数将 onRejected 回调函数放入微任务队列中。

Promise 的状态为 Pending 时,我们将 onFulfilledonRejected 回调函数保存到 onFulfilledCallbacksonRejectedCallbacks 数组中,并在异步操作完成后执行。

然后,我们返回一个新的 Promise 实例,该实例包含了一个 executor 函数。在 executor 函数中,我们根据当前 Promise 的状态决定调用 onFulfilledonRejected 回调函数,并将执行结果传递给 resolvereject 函数。

最后,我们实现了catch函数,Promise中的catch方法是用于捕获promise对象的拒绝状态(rejected)的回调函数,它相当于调用then方法时传入一个undefined作为第一个参数,而将回调函数作为第二个参数。

使用手写Promise

现在,我们可以使用手写的 Promise 类来处理异步操作了。下面是一个简单的例子:

javascript
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello, world!'); }, 1000); }); promise .then((result) => { console.log(result); return 'Goodbye, world!'; }) .then((result) => { console.log(result); }) .catch((error) => { console.error(error); });

在这个例子中,我们创建了一个 Promise 实例,并在 1 秒钟后将状态设置为 Fulfilled,并返回一个字符串。

然后,我们链式调用了两个 then 方法,第一个方法打印了字符串并返回了一个新的字符串,第二个方法又打印了新的字符串。

最后,我们调用了 catch 方法,以处理任何可能发生的错误。

结论

Promise 是一种非常强大的异步编程技术,可以使我们更加轻松地管理异步代码。通过手写实现 Promise,我们可以更好地理解 Promise 的工作原理,并更加深入地了解 JavaScript 的异步编程模型。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:CreatorRay

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!