返回

深层探究:手写符合 Promise/A+ 规范的 Promise 源码,解析异步编程精髓

前端

Promise 是 JavaScript 中异步编程的核心,也是前端面试的高频问题。要成为一名优秀的前端工程师,掌握 Promise 及其底层实现原理至关重要。

本文将从 Promise/A+ 规范解读入手,带你深入理解 Promise 的工作原理。随后,我们将手写一个符合 Promise/A+ 规范的 Promise 源码,让你对 Promise 的内部机制有更深刻的认识。

Promise/A+ 规范解读

Promise/A+ 规范定义了 Promise 对象的行为和交互方式,确保不同实现的 Promise 对象具有统一的语义。该规范包含以下几个关键概念:

  • Promise 对象: 表示一个异步操作的最终完成或失败及其结果值。
  • Promise 状态: Promise 对象有三种状态:Pending(等待)、Fulfilled(已完成)和 Rejected(已失败)。
  • Promise 回调函数: then() 方法用于注册回调函数,当 Promise 对象状态改变时,这些回调函数会被调用。
  • Promise 链式调用: then() 方法可以返回一个新的 Promise 对象,从而形成 Promise 链。

手写 Promise 源码

为了更深入地理解 Promise 的工作原理,我们现在将手写一个符合 Promise/A+ 规范的 Promise 源码。

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

    // 执行器函数的调用,并传入 resolve 和 reject 两个函数
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (err) {
      this.reject(err);
    }
  }

  resolve(value) {
    // 只能从 pending 状态变为 fulfilled 状态
    if (this.state !== "pending") {
      return;
    }

    this.state = "fulfilled";
    this.value = value;

    // 依次执行成功的回调函数
    this.onFulfilledCallbacks.forEach((callback) => {
      callback(this.value);
    });
  }

  reject(reason) {
    // 只能从 pending 状态变为 rejected 状态
    if (this.state !== "pending") {
      return;
    }

    this.state = "rejected";
    this.reason = reason;

    // 依次执行失败的回调函数
    this.onRejectedCallbacks.forEach((callback) => {
      callback(this.reason);
    });
  }

  then(onFulfilled, onRejected) {
    // 返回一个新的 Promise 对象
    return new Promise((resolve, reject) => {
      // 处理同步情况
      if (this.state === "fulfilled") {
        setTimeout(() => {
          try {
            // 执行成功的回调函数
            const value = onFulfilled(this.value);
            resolve(value);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else if (this.state === "rejected") {
        setTimeout(() => {
          try {
            // 执行失败的回调函数
            const reason = onRejected(this.reason);
            resolve(reason);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else {
        // 处理异步情况
        // 将成功的回调函数存储起来
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              // 执行成功的回调函数
              const value = onFulfilled(this.value);
              resolve(value);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });

        // 将失败的回调函数存储起来
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              // 执行失败的回调函数
              const reason = onRejected(this.reason);
              resolve(reason);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
      }
    });
  }

  // 辅助方法,用于 Promise 链式调用的终止
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  // 辅助方法,用于 Promise 的并行处理
  static all(promises) {
    return new Promise((resolve, reject) => {
      // 结果数组,用于存储每个 Promise 的结果
      const results = [];

      // 记录已完成的 Promise 的数量
      let completedCount = 0;

      // 遍历每个 Promise
      promises.forEach((promise, index) => {
        // 将 Promise 的结果存储在结果数组中
        promise
          .then((value) => {
            results[index] = value;
            completedCount++;

            // 当所有 Promise 都已完成时,resolve 最终的 Promise
            if (completedCount === promises.length) {
              resolve(results);
            }
          })
          .catch((reason) => {
            // 只要有一个 Promise 失败,就 reject 最终的 Promise
            reject(reason);
          });
      });
    });
  }

  // 辅助方法,用于 Promise 的串行处理
  static race(promises) {
    return new Promise((resolve, reject) => {
      // 遍历每个 Promise
      promises.forEach((promise) => {
        // 只要有一个 Promise 完成或失败,就 resolve 或 reject 最终的 Promise
        promise
          .then((value) => {
            resolve(value);
          })
          .catch((reason) => {
            reject(reason);
          });
      });
    });
  }
}

使用手写的 Promise

const promise = new Promise((resolve, reject) => {
  // 模拟异步操作
  setTimeout(() => {
    resolve("Hello, Promise!");
  }, 1000);
});

promise
  .then((value) => {
    console.log(value); // 输出: "Hello, Promise!"
  })
  .catch((reason) => {
    console.log(reason); // 不会被调用
  });

结语

通过手写 Promise 源码,我们对 Promise 的工作原理有了更深入的理解。Promise 是 JavaScript 中异步编程的核心,掌握其原理和用法对前端工程师来说至关重要。希望本文能帮助读者更好地理解 Promise,并在实际项目中熟练使用它。