返回

掌控异步编程的利器:手动实现Promise的魅力

前端

Promise,全称Promises/A+,是JavaScript中用于处理异步编程的神奇工具。它可以将异步操作转为可控、可管理的单位,使开发人员能够以同步的方式编写异步代码。这不仅提高了代码的可读性,也极大地简化了异步编程的复杂性。

构建基础版Promise

Promise的实现原理并不复杂,让我们从头开始构建一个基础版的Promise。

class Promise {
  constructor(executor) {
    this.status = "pending"; // 初始状态为pending
    this.value = null; // 存放最终结果
    this.reason = null; // 存放错误信息
    this.onFulfilledCallbacks = []; // 存放成功回调函数
    this.onRejectedCallbacks = []; // 存放失败回调函数

    // 立即执行executor,并传入resolve和reject两个函数
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  resolve(value) {
    if (this.status !== "pending") return;

    this.status = "fulfilled";
    this.value = value;

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

  reject(reason) {
    if (this.status !== "pending") return;

    this.status = "rejected";
    this.reason = reason;

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

  then(onFulfilled, onRejected) {
    // 如果onFulfilled不是函数,则返回当前的Promise
    if (typeof onFulfilled !== "function") {
      return this;
    }

    // 如果onRejected不是函数,则返回当前的Promise
    if (typeof onRejected !== "function") {
      return this;
    }

    // 创建新的Promise
    const newPromise = new Promise((resolve, reject) => {
      // 成功回调函数
      const fulfilledCallback = (value) => {
        try {
          // 调用onFulfilled,并传入当前Promise的value
          const result = onFulfilled(value);

          // 根据result决定是resolve还是reject
          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          // 如果onFulfilled抛出错误,则reject新的Promise
          reject(error);
        }
      };

      // 失败回调函数
      const rejectedCallback = (reason) => {
        try {
          // 调用onRejected,并传入当前Promise的reason
          const result = onRejected(reason);

          // 根据result决定是resolve还是reject
          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          // 如果onRejected抛出错误,则reject新的Promise
          reject(error);
        }
      };

      // 根据当前Promise的状态,执行对应的回调函数
      if (this.status === "fulfilled") {
        fulfilledCallback(this.value);
      } else if (this.status === "rejected") {
        rejectedCallback(this.reason);
      } else {
        // 如果当前Promise处于pending状态,则将回调函数暂存起来
        this.onFulfilledCallbacks.push(fulfilledCallback);
        this.onRejectedCallbacks.push(rejectedCallback);
      }
    });

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

异步处理和发布订阅

Promise的强大之处在于它可以处理异步操作。我们可以利用发布订阅的方式将回调函数暂存起来,最后再执行。这可以极大地简化异步编程的复杂性。

// 创建一个Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功!");
  }, 1000);
});

// 订阅成功回调函数
promise.then((result) => {
  console.log(result); // 输出:成功!
});

在上面的例子中,我们创建了一个Promise,并在1秒后resolve了一个值。然后,我们订阅了成功回调函数,并在Promise resolve后执行该回调函数,从而输出结果。

链式调用

Promise还支持链式调用,这使得我们能够以一种简洁、可读的方式编写异步代码。

// 创建一个Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功!");
  }, 1000);
});

// 链式调用then方法
promise
  .then((result) => {
    console.log(result); // 输出:成功!
    return result + " world"; // 返回一个新的Promise
  })
  .then((result) => {
    console.log(result); // 输出:成功! world
  });

在上面的例子中,我们使用链式调用了then方法。在第一个then方法中,我们输出结果并返回一个新的Promise。在第二个then方法中,我们输出新的Promise的结果。这使得我们可以将多个异步操作串联起来,并以一种简洁的方式处理结果。

结语

Promise是JavaScript中用于处理异步编程的神奇工具。它可以将异步操作转为可控、可管理的单位,使开发人员能够以同步的方式编写异步代码。这不仅提高了代码的可读性,也极大地简化了异步编程的复杂性。通过本文,您已经掌握了Promise的基础实现、异步处理和链式调用的原理。现在,您已经准备好将Promise应用到您的项目中,并享受异步编程带来的便利和乐趣。