返回

带着手写 Promise,拨开异步编程的迷雾

前端

走进 Promise 的世界

Promise 的出现,为我们处理异步操作带来了新的可能。它提供了一个统一的 API,让我们可以轻松地处理异步任务的结果,并且可以对这些结果进行链式操作,从而使代码更加简洁和易于理解。

手把手构建 Promise

为了更好地理解 Promise 的工作原理,我们不妨亲手构建一个简易版的 Promise。首先,我们需要定义一个 Promise 构造函数,它接受一个执行器函数作为参数。这个执行器函数包含两个参数:resolve 和 reject,它们分别用于将 Promise 的状态从“等待”变为“成功”或“失败”。

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

  // 执行器函数
  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }
}

在 Promise 构造函数中,我们定义了 Promise 的初始状态、值、原因,以及两个用于存储回调函数的数组。然后,我们使用 try...catch 语句来执行执行器函数。如果执行器函数执行成功,则调用 resolve 函数将 Promise 的状态从“等待”变为“成功”;如果执行器函数执行失败,则调用 reject 函数将 Promise 的状态从“等待”变为“失败”。

then 方法揭秘

Promise 的 then 方法用于处理 Promise 的结果。它接受两个参数:onFulfilled 和 onRejected,它们分别用于处理 Promise 的成功和失败状态。

Promise.prototype.then = function(onFulfilled, onRejected) {
  // 如果 onFulfilled 不是函数,则使用默认函数
  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function(value) {
    return value;
  };

  // 如果 onRejected 不是函数,则使用默认函数
  onRejected = typeof onRejected === "function" ? onRejected : function(reason) {
    throw reason;
  };

  // 根据 Promise 的状态,将回调函数推入相应的数组
  if (this.state === "fulfilled") {
    setTimeout(() => {
      onFulfilled(this.value);
    }, 0);
  } else if (this.state === "rejected") {
    setTimeout(() => {
      onRejected(this.reason);
    }, 0);
  } else {
    this.onFulfilledCallbacks.push(onFulfilled);
    this.onRejectedCallbacks.push(onRejected);
  }

  // 返回一个新的 Promise
  return new Promise((resolve, reject) => {
    // 在 onFulfilled 回调函数中,调用 resolve 函数
    this.onFulfilledCallbacks.push((value) => {
      try {
        const result = onFulfilled(value);
        resolve(result);
      } catch (error) {
        reject(error);
      }
    });

    // 在 onRejected 回调函数中,调用 reject 函数
    this.onRejectedCallbacks.push((reason) => {
      try {
        const result = onRejected(reason);
        resolve(result);
      } catch (error) {
        reject(error);
      }
    });
  });
};

在 then 方法中,我们首先检查 onFulfilled 和 onRejected 是否为函数,如果不是,则使用默认函数。然后,根据 Promise 的状态,将回调函数推入相应的数组。如果 Promise 的状态为“成功”,则将 onFulfilled 回调函数推入 onFulfilledCallbacks 数组;如果 Promise 的状态为“失败”,则将 onRejected 回调函数推入 onRejectedCallbacks 数组。如果 Promise 的状态为“等待”,则将 onFulfilled 和 onRejected 回调函数分别推入 onFulfilledCallbacks 和 onRejectedCallbacks 数组。

最后,我们返回一个新的 Promise,这个新的 Promise 的状态由 onFulfilled 和 onRejected 回调函数决定。如果 onFulfilled 回调函数执行成功,则将 Promise 的状态变为“成功”;如果 onRejected 回调函数执行成功,则将 Promise 的状态变为“失败”。

Promise 的应用场景

Promise 在实际开发中有着广泛的应用场景,比如:

  • 异步数据请求: Promise 可以轻松地处理异步数据请求,例如使用 fetch 函数发起 HTTP 请求。
  • 定时器: Promise 可以用于处理定时器,例如使用 setTimeout 函数来延迟执行某个操作。
  • 事件监听: Promise 可以用于监听事件,例如使用 addEventListener 函数来监听 DOM 事件。

结语

Promise 作为异步编程的利器,为开发者带来了更加便捷和高效的开发体验。通过手写一个简易版的 Promise,我们可以对 Promise 的工作原理有了更深入的理解。希望本文能够帮助你更好地掌握 Promise,并将其应用到实际开发中。