返回

深入剖析Promise 原理:逐步实现一个 Promise

前端

Promise 原理与实现

Promise 是 JavaScript 中用来处理异步操作的神奇工具,它可以帮助我们更优雅地处理异步代码。它到底是如何工作的呢?我们一起来一步步实现一个简单的 Promise。

首先,我们需要定义一个 Promise 构造函数。它接收一个函数作为参数,这个函数有两个参数:resolve 和 reject。resolve 用于表示异步操作成功,reject 用于表示异步操作失败。

function Promise(executor) {
  this.state = 'pending';
  this.value = undefined;
  this.reason = undefined;
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];

  const resolve = (value) => {
    if (this.state !== 'pending') return;
    this.state = 'fulfilled';
    this.value = value;
    this.onFulfilledCallbacks.forEach((callback) => {
      callback(value);
    });
  };

  const reject = (reason) => {
    if (this.state !== 'pending') return;
    this.state = 'rejected';
    this.reason = reason;
    this.onRejectedCallbacks.forEach((callback) => {
      callback(reason);
    });
  };

  executor(resolve, reject);
}

现在我们有了一个 Promise 构造函数,它可以用来创建一个 Promise 对象。我们可以通过调用 Promise 构造函数并传入一个执行器函数来创建一个 Promise 对象。执行器函数会在 Promise 对象创建时立即执行,它可以用来执行异步操作,并通过调用 resolve 或 reject 来改变 Promise 对象的状态。

状态变化与回调函数

Promise 对象的状态只能是三种:pending、fulfilled 和 rejected。状态一旦改变,就不可逆转。如果 Promise 对象的状态从 pending 变为 fulfilled,则会调用所有之前注册的 onFulfilled 回调函数;如果 Promise 对象的状态从 pending 变为 rejected,则会调用所有之前注册的 onRejected 回调函数。

我们可以通过调用 then 方法来注册回调函数。then 方法接收两个参数:onFulfilled 和 onRejected,它们分别表示 Promise 对象状态为 fulfilled 和 rejected 时要执行的回调函数。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功了!');
  }, 1000);
});

promise.then(
  (value) => {
    console.log(value); // 输出:'成功了!'
  },
  (reason) => {
    console.log(reason); // 不会被调用
  }
);

在上面的示例中,我们创建了一个 Promise 对象,并注册了两个回调函数。当 Promise 对象的状态变为 fulfilled 时,第一个回调函数会被调用;当 Promise 对象的状态变为 rejected 时,第二个回调函数会被调用。

链式调用与回调地狱

Promise 对象支持链式调用,这使得我们可以将多个 Promise 对象连接起来,形成一个链式结构。链式调用可以帮助我们避免回调地狱,让代码更清晰、更易维护。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功了!');
  }, 1000);
});

const promise2 = promise1.then((value) => {
  console.log(value); // 输出:'成功了!'
  return '另一个成功了!';
});

promise2.then((value) => {
  console.log(value); // 输出:'另一个成功了!'
});

在上面的示例中,我们创建了一个 Promise 对象 promise1,并注册了一个回调函数。然后,我们通过调用 promise1.then 方法创建了一个新的 Promise 对象 promise2。promise2 的回调函数中,我们打印了 promise1 的值,并返回了一个新的值。最后,我们通过调用 promise2.then 方法注册了另一个回调函数,该回调函数打印了 promise2 的值。

链式调用使得我们可以将多个异步操作连接起来,形成一个清晰、易维护的代码结构。它避免了回调地狱,让代码更易于阅读和理解。