返回

从零构建 Promise:分步指南

前端

引言

Promise 作为一种成熟的异步编程解决方案,以其简洁易用、强大的错误处理机制和可组合性而著称。虽然理解和使用 Promise 并不难,但要真正掌握它们,还需要更深入地了解其底层工作原理。通过亲自动手实现 Promise,你可以获得宝贵的见解,并提升对异步编程概念的掌握程度。

第 1 步:初始化

首先,我们需要一个构造函数来创建 Promise 实例。Promise 构造函数接受一个 executor 函数作为参数,该函数接收 resolve 和 reject 两个回调函数,用于在 Promise 完成或拒绝时调用。

function Promise(executor) {
  this.state = 'pending';
  this.value = undefined;
  this.error = undefined;
  this.onResolveCallbacks = [];
  this.onRejectCallbacks = [];

  // 执行 executor 函数,传入 resolve 和 reject 回调函数
  executor(resolve, reject);
}

第 2 步:解析和拒绝

resolve 和 reject 函数用于改变 Promise 的状态。resolve 将 Promise 的状态设置为 "fulfilled" 并设置一个值,而 reject 将状态设置为 "rejected" 并设置一个错误。

Promise.prototype.resolve = function(value) {
  if (this.state !== 'pending') return;

  this.state = 'fulfilled';
  this.value = value;

  // 调用所有 onResolveCallbacks
  for (let callback of this.onResolveCallbacks) {
    callback(value);
  }
};

Promise.prototype.reject = function(error) {
  if (this.state !== 'pending') return;

  this.state = 'rejected';
  this.error = error;

  // 调用所有 onRejectCallbacks
  for (let callback of this.onRejectCallbacks) {
    callback(error);
  }
};

第 3 步:then() 方法

then() 方法是 Promise 的核心,它允许你为成功或失败的情况指定回调函数。

Promise.prototype.then = function(onResolve, onReject) {
  // 如果 onResolve 或 onReject 未提供,则使用默认的回调函数
  if (typeof onResolve !== 'function') {
    onResolve = value => value;
  }
  if (typeof onReject !== 'function') {
    onReject = error => { throw error; };
  }

  // 创建一个新的 Promise 来包装回调函数的结果
  const newPromise = new Promise(() => {});

  // 如果 Promise 已完成,则立即执行回调函数
  if (this.state === 'fulfilled') {
    setTimeout(() => {
      try {
        const result = onResolve(this.value);
        newPromise.resolve(result);
      } catch (error) {
        newPromise.reject(error);
      }
    }, 0);
  } else if (this.state === 'rejected') {
    setTimeout(() => {
      try {
        const result = onReject(this.error);
        newPromise.resolve(result);
      } catch (error) {
        newPromise.reject(error);
      }
    }, 0);
  } else {
    // 如果 Promise 仍处于待定状态,则将回调函数添加到 onResolveCallbacks 或 onRejectCallbacks 数组中
    this.onResolveCallbacks.push(() => {
      setTimeout(() => {
        try {
          const result = onResolve(this.value);
          newPromise.resolve(result);
        } catch (error) {
          newPromise.reject(error);
        }
      }, 0);
    });
    this.onRejectCallbacks.push(() => {
      setTimeout(() => {
        try {
          const result = onReject(this.error);
          newPromise.resolve(result);
        } catch (error) {
          newPromise.reject(error);
        }
      }, 0);
    });
  }

  // 返回新的 Promise
  return newPromise;
};

第 4 步:使用 Promise

现在我们已经实现了 Promise,就可以开始使用它来编写异步代码了。以下是一个示例,说明如何使用 Promise 获取数据的异步函数:

const getData = () => {
  return new Promise((resolve, reject) => {
    // 模拟异步操作
    setTimeout(() => {
      if (Math.random() < 0.5) {
        resolve('数据获取成功');
      } else {
        reject('数据获取失败');
      }
    }, 1000);
  });
};

getData()
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.log(error);
  });

结语

通过从零构建 Promise,你已经深入了解了 Promise 的内部工作原理和使用方式。这不仅增强了你的 JavaScript 技能,还为你提供了编写健壮、可维护的异步代码的宝贵见解。

掌握 Promise 将为你打开异步编程的大门,让你能够轻松处理并发操作、提高代码的可读性和提高应用程序的性能。继续探索 Promise 的高级特性,例如 Promise.all()、Promise.race() 和 async/await,以进一步提升你的异步编程能力。