返回

手写Promise——解锁异步编程的利器

前端

异步编程利器:深入解析 Promise

在现代前端开发中,异步编程已经成为必不可少的组成部分。我们不断处理来自服务器的请求、用户交互、动画效果等异步任务。这些任务可能需要一段时间才能完成,我们不能让整个应用程序停在那里等待它们。这就是 Promise 发挥作用的地方,它是一种处理异步任务的机制,让我们能够以同步的方式编写代码。

什么是 Promise?

Promise 是一个对象,它表示一个异步操作的最终完成或失败状态。它提供了一种机制来处理异步任务,并允许我们像编写同步代码一样编写代码。

创建一个 Promise

要创建一个 Promise,可以使用 new Promise() 函数。该函数接收一个执行器函数作为参数,该函数有两个参数:resolverejectresolve 用于表示异步操作成功完成,而 reject 用于表示异步操作失败。

Promise 的状态

Promise 有三个状态:

  • pending: 表示 Promise 尚未完成,正在等待异步操作完成。
  • fulfilled: 表示 Promise 成功完成,异步操作的结果可以通过 .then() 方法获取。
  • rejected: 表示 Promise 失败,异步操作抛出了一个异常,可以通过 .catch() 方法获取错误信息。

使用 Promise

我们可以使用 .then().catch() 方法来处理 Promise 的状态。

  • .then() 方法: 在 Promise 成功完成时调用,用于获取异步操作的结果。
  • .catch() 方法: 在 Promise 失败时调用,用于获取错误信息。

Promise 的优点

Promise 相比于传统的回调函数具有以下优点:

  • 代码更清晰、更易读: Promise 避免了回调函数的嵌套,使代码更易于维护。
  • 支持链式调用: Promise 支持链式调用,使代码更具可读性和可维护性。

手写 Promise

为了更好地理解 Promise 的工作原理,让我们一起手写一个 Promise。

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

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;

        this.onFulfilledCallbacks.forEach(fn => fn(value));
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;

        this.onRejectedCallbacks.forEach(fn => fn(reason));
      }
    };

    executor(resolve, reject);
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    const promise = new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        const result = onFulfilled(this.value);

        if (result instanceof Promise) {
          result.then(resolve, reject);
        } else {
          resolve(result);
        }
      } else if (this.state === 'rejected') {
        const error = onRejected(this.reason);

        if (error instanceof Promise) {
          error.then(resolve, reject);
        } else {
          reject(error);
        }
      } else {
        this.onFulfilledCallbacks.push(() => {
          const result = onFulfilled(this.value);

          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        });

        this.onRejectedCallbacks.push(() => {
          const error = onRejected(this.reason);

          if (error instanceof Promise) {
            error.then(resolve, reject);
          } else {
            reject(error);
          }
        });
      }
    });

    return promise;
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
}

常见问题解答

  • 为什么使用 Promise?

    • Promise 使异步编程更加清晰、可读和可维护。
  • 如何处理异步任务?

    • 使用 Promise 创建一个异步任务,然后使用 .then().catch() 方法处理其状态。
  • Promise 和回调函数有什么区别?

    • Promise 避免了回调函数的嵌套,使代码更易于阅读和维护。
  • 如何创建自己的 Promise?

    • 使用 new Promise() 函数创建一个 Promise,并传入一个执行器函数,该函数包含 resolvereject 方法。
  • 如何使用链式调用?

    • Promise 支持链式调用,允许你连续处理多个异步任务,而不需要嵌套回调函数。