返回

手写 Promise(上):打破对现有实现的依赖

前端

在现代 JavaScript 中,Promise 是处理异步编程的利器。它使代码更容易理解和维护,并提供了对异步操作的更细粒度的控制。

然而,许多开发人员只是简单地依赖于 Promise 的现有实现,而没有深入了解它的内部工作原理。这可能会导致在使用 Promise 时遇到问题或产生误解。

手写 Promise 可以帮助我们更好地理解 Promise,并能更灵活地运用 Promise 解决实际问题。

Promise 简介

Promise 是一个表示异步操作最终完成或失败的 JavaScript 对象。它可以被用于处理异步任务的结果,并可以被链接起来形成 Promise 链。

Promise 有三种状态:

  • 已决状态(fulfilled):当异步操作成功完成时,Promise 会进入已决状态。
  • 已驳回状态(rejected):当异步操作失败时,Promise 会进入已驳回状态。
  • 待定状态(pending):当异步操作还没有完成时,Promise 会处于待定状态。

手写 Promise

现在,让我们一步一步地实现一个简单的 Promise。

首先,我们需要定义一个 Promise 构造函数。这个构造函数接收一个执行器函数作为参数。执行器函数有两个参数:resolve 和 reject。

function Promise(executor) {
  // Promise 的当前状态
  this.state = 'pending';
  // Promise 的结果
  this.value = undefined;
  // Promise 的失败原因
  this.reason = undefined;
  // Promise 的成功回调函数队列
  this.onFulfilledCallbacks = [];
  // Promise 的失败回调函数队列
  this.onRejectedCallbacks = [];

  // 执行执行器函数
  executor(resolve, reject);
}

在执行器函数中,我们可以调用 resolve 或 reject 来改变 Promise 的状态。

function resolve(value) {
  // 将 Promise 的状态改为已决状态
  this.state = 'fulfilled';
  // 将 Promise 的结果设置为 value
  this.value = value;
  // 执行成功回调函数队列中的函数
  this.onFulfilledCallbacks.forEach(callback => callback(value));
}

function reject(reason) {
  // 将 Promise 的状态改为已驳回状态
  this.state = 'rejected';
  // 将 Promise 的失败原因设置为 reason
  this.reason = reason;
  // 执行失败回调函数队列中的函数
  this.onRejectedCallbacks.forEach(callback => callback(reason));
}

然后,我们需要定义 then 方法。then 方法接收两个参数:onFulfilled 和 onRejected。这两个参数都是函数,分别用于处理 Promise 的成功和失败。

Promise.prototype.then = function(onFulfilled, onRejected) {
  // 如果 onFulfilled 不是函数,则将其设置为一个函数,该函数返回 Promise 的结果
  if (typeof onFulfilled !== 'function') {
    onFulfilled = function(value) {
      return value;
    };
  }

  // 如果 onRejected 不是函数,则将其设置为一个函数,该函数返回 Promise 的失败原因
  if (typeof onRejected !== 'function') {
    onRejected = function(reason) {
      throw reason;
    };
  }

  // 创建一个新的 Promise
  const newPromise = new Promise(() => {});

  // 将成功回调函数添加到成功回调函数队列
  this.onFulfilledCallbacks.push(function(value) {
    // 调用 onFulfilled 函数并获取结果
    const result = onFulfilled(value);

    // 如果 result 是一个 Promise,则将 newPromise 的状态设置为 result 的状态
    if (result instanceof Promise) {
      result.then(
        // 将 newPromise 的状态设置为已决状态
        value => {
          newPromise.resolve(value);
        },
        // 将 newPromise 的状态设置为已驳回状态
        reason => {
          newPromise.reject(reason);
        }
      );
    } else {
      // 将 newPromise 的状态设置为已决状态
      newPromise.resolve(result);
    }
  });

  // 将失败回调函数添加到失败回调函数队列
  this.onRejectedCallbacks.push(function(reason) {
    // 调用 onRejected 函数并获取结果
    const result = onRejected(reason);

    // 如果 result 是一个 Promise,则将 newPromise 的状态设置为 result 的状态
    if (result instanceof Promise) {
      result.then(
        // 将 newPromise 的状态设置为已决状态
        value => {
          newPromise.resolve(value);
        },
        // 将 newPromise 的状态设置为已驳回状态
        reason => {
          newPromise.reject(reason);
        }
      );
    } else {
      // 将 newPromise 的状态设置为已决状态
      newPromise.resolve(result);
    }
  });

  // 返回 newPromise
  return newPromise;
};

最后,我们需要定义 catch 方法。catch 方法接收一个参数:onRejected。这个参数是用于处理 Promise 的失败的函数。

Promise.prototype.catch = function(onRejected) {
  return this.then(undefined, onRejected);
};

至此,我们就手写了一个简单的 Promise。我们可以使用这个 Promise 来处理异步任务的结果,并可以将其链接起来形成 Promise 链。

结语

手写 Promise 可以帮助我们更好地理解 Promise 的内部工作原理,并能更灵活地运用 Promise 解决实际问题。本文提供了详细的手写 Promise 实现步骤,读者可以按照这些步骤自己实现一个 Promise。

在实际开发中,我们通常不会自己实现 Promise,而是使用现有的 Promise 实现,如原生 Promise 或第三方 Promise 库。但是,手写 Promise 可以帮助我们加深对 Promise 的理解,并能让我们更灵活地运用 Promise 解决实际问题。