返回

掌握 Promise 精髓,2 天内亲手实现 Promise 类

前端

前言

在 JavaScript 中,Promise 是一个非常重要的概念,它可以帮助我们处理异步操作,让代码更具可读性和可维护性。然而,对于很多初学者来说,Promise 可能是一个比较陌生的概念,他们可能不知道如何使用 Promise,也不知道如何实现一个自己的 Promise 类。

本文将带领你从零开始,一步一步地实现一个自己的 Promise 类,并在此基础上进行扩展,使之能够满足生产环境的需求。通过本文,你将对 Promise 有一个更深入的理解,并能够在你的项目中灵活运用 Promise,提升你的开发效率和代码质量。

第 1 步:了解 Promise 的基本概念

Promise 是一个对象,它代表一个异步操作的最终完成或失败的结果。Promise 有三种状态:

  • 待定(pending):这是 Promise 的初始状态,表示异步操作尚未完成。
  • 已完成(fulfilled):表示异步操作已成功完成,并带有结果值。
  • 已拒绝(rejected):表示异步操作已失败,并带有错误信息。

Promise 可以通过 then() 方法来添加回调函数,当 Promise 的状态发生变化时,相应的回调函数就会被调用。

第 2 步:实现一个简单的 Promise 类

现在,我们来实现一个简单的 Promise 类。这个类将包含以下方法:

  • constructor(executor):Promise 的构造函数,接受一个执行器(executor)函数作为参数。执行器函数将立即执行,并传入两个参数:resolvereject
  • then(onFulfilled, onRejected):添加回调函数的方法。当 Promise 的状态发生变化时,相应的回调函数就会被调用。
  • catch(onRejected):添加错误处理回调函数的方法。当 Promise 被拒绝时,错误处理回调函数就会被调用。
class Promise {
  private state: 'pending' | 'fulfilled' | 'rejected' = 'pending';
  private value: any;
  private reason: any;
  private onFulfilledCallbacks: Array<Function> = [];
  private onRejectedCallbacks: Array<Function> = [];

  constructor(executor: (resolve: (value: any) => void, reject: (reason: any) => void) => void) {
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  then(onFulfilled?: (value: any) => void, onRejected?: (reason: any) => void): Promise {
    return new Promise((resolve, reject) => {
      this.onFulfilledCallbacks.push(() => {
        try {
          const result = onFulfilled ? onFulfilled(this.value) : this.value;
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });

      this.onRejectedCallbacks.push(() => {
        try {
          const result = onRejected ? onRejected(this.reason) : this.reason;
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });
    });
  }

  catch(onRejected: (reason: any) => void): Promise {
    return this.then(undefined, onRejected);
  }

  resolve(value: any) {
    if (this.state !== 'pending') {
      return;
    }

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

    this.onFulfilledCallbacks.forEach((callback) => {
      callback();
    });
  }

  reject(reason: any) {
    if (this.state !== 'pending') {
      return;
    }

    this.state = 'rejected';
    this.reason = reason;

    this.onRejectedCallbacks.forEach((callback) => {
      callback();
    });
  }
}

第 3 步:扩展 Promise 类

现在,我们已经实现了一个简单的 Promise 类。然而,在实际开发中,我们可能需要对 Promise 类进行一些扩展,以满足不同的需求。

1. 添加 finally() 方法

finally() 方法允许我们在 Promise 不论是成功还是失败,都会执行一个指定的回调函数。这个方法对于一些场景非常有用,比如清理资源或关闭数据库连接等。

class Promise {
  // 省略前面的代码

  finally(onFinally: () => void): Promise {
    return this.then(
      (value) => {
        onFinally();
        return value;
      },
      (reason) => {
        onFinally();
        throw reason;
      }
    );
  }
}

2. 添加 all() 方法

all() 方法可以同时处理多个 Promise,并返回一个 Promise,该 Promise 在所有输入 Promise 都完成或有一个 Promise 被拒绝后才完成。

class Promise {
  // 省略前面的代码

  static all(promises: Array<Promise>): Promise {
    return new Promise((resolve, reject) => {
      const results: Array<any> = [];
      let pendingCount = promises.length;

      promises.forEach((promise, index) => {
        promise.then(
          (value) => {
            results[index] = value;
            pendingCount--;
            if (pendingCount === 0) {
              resolve(results);
            }
          },
          (reason) => {
            reject(reason);
          }
        );
      });
    });
  }
}

3. 添加 race() 方法

race() 方法可以同时处理多个 Promise,并返回一个 Promise,该 Promise 在第一个输入 Promise 完成或被拒绝后立即完成或被拒绝。

class Promise {
  // 省略前面的代码

  static race(promises: Array<Promise>): Promise {
    return new Promise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            reject(reason);
          }
        );
      });
    });
  }
}

结语

至此,我们已经实现了一个自己的 Promise 类,并在此基础上进行了扩展。通过本文,你应该对 Promise 有了一个更深入的理解,并能够在你的项目中灵活运用 Promise,提升你的开发效率和代码质量。

希望本文对你有所帮助。如果你有任何问题,欢迎在评论区留言。