返回

揭秘 Promise A+ 规范:Typescript实现指南

前端

JavaScript 中使用 TypeScript 实现 Promise

什么是 Promise?

在现代 JavaScript 应用程序中,异步编程至关重要。Promise 是一种强大的工具,可用于优雅地处理异步操作。它允许你编写顺序执行代码,即使存在异步操作。

Promise A+ 规范

为了确保 Promise 行为的一致性,JavaScript 语言定义了 Promise A+ 规范。该规范规定了 Promise 对象必须遵循的行为和方法。

使用 TypeScript 实现 Promise 类

TypeScript 是一种流行的 JavaScript 超集,它允许你使用类型注解和面向对象编程。我们可以使用 TypeScript 实现自己的 Promise 类来更深入地了解 Promise 的工作原理。

代码示例:

class Promise<T> {
  private state: 'pending' | 'fulfilled' | 'rejected';
  private value: T | undefined;
  private reason: any | undefined;
  private onFulfilledCallbacks: Array<Function>;
  private onRejectedCallbacks: Array<Function>;

  constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {
    this.state = 'pending';
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  public then<TResult1 = T, TResult2 = never>(onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2> {
    const promise = new Promise<TResult1 | TResult2>();

    this.onFulfilledCallbacks.push(() => {
      this._handleResolution(promise, onFulfilled, this.value);
    });

    this.onRejectedCallbacks.push(() => {
      this._handleRejection(promise, onRejected, this.reason);
    });

    return promise;
  }

  public catch<TResult = never>(onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult> {
    return this.then(undefined, onRejected);
  }

  public finally(onFinally?: (() => void) | undefined | null): Promise<T> {
    const promise = new Promise<T>(() => {});

    this.then(() => {
      onFinally?.();
      return promise;
    }, () => {
      onFinally?.();
      return promise;
    });

    return promise;
  }

  private _handleResolution<TResult1 = T, TResult2 = never>(promise: Promise<TResult1 | TResult2>, onFulfilled: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, value: T): void {
    if (typeof onFulfilled !== 'function') {
      promise.resolve(value);
      return;
    }

    let result: TResult1 | PromiseLike<TResult1>;
    try {
      result = onFulfilled(value);
    } catch (error) {
      promise.reject(error);
      return;
    }

    this._settlePromise(promise, result);
  }

  private _handleRejection<TResult1 = T, TResult2 = never>(promise: Promise<TResult1 | TResult2>, onRejected: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null, reason: any): void {
    if (typeof onRejected !== 'function') {
      promise.reject(reason);
      return;
    }

    let result: TResult2 | PromiseLike<TResult2>;
    try {
      result = onRejected(reason);
    } catch (error) {
      promise.reject(error);
      return;
    }

    this._settlePromise(promise, result);
  }

  private _settlePromise<TResult1 = T, TResult2 = never>(promise: Promise<TResult1 | TResult2>, result: TResult1 | PromiseLike<TResult1>): void {
    if (promise === result) {
      promise.reject(new TypeError('Chaining cycle detected for promise!'));
      return;
    }

    if (result instanceof Promise) {
      result.then((value) => {
        this._handleResolution(promise, undefined, value);
      }, (reason) => {
        this._handleRejection(promise, undefined, reason);
      });
      return;
    }

    promise._state = 'fulfilled';
    promise._value = result;
    this._callCallbacks(promise);
  }

  private _callCallbacks(promise: Promise<T>): void {
    if (promise._state === 'fulfilled') {
      this._onFulfilledCallbacks.forEach((callback) => {
        callback();
      });
    } else {
      this._onRejectedCallbacks.forEach((callback) => {
        callback();
      });
    }
  }

  public resolve(value?: T | PromiseLike<T>): void {
    if (this._state !== 'pending') {
      return;
    }

    this._state = 'fulfilled';
    this._value = value;
    this._callCallbacks(this);
  }

  public reject(reason?: any): void {
    if (this._state !== 'pending') {
      return;
    }

    this._state = 'rejected';
    this._reason = reason;
    this._callCallbacks(this);
  }
}

使用 Promise

一旦你有了自定义的 Promise 实现,你就可以在你的 JavaScript 应用程序中使用它。以下是使用 Promise 的示例:

const promise = new Promise((resolve, reject) => {
  // 执行异步操作
  if (success) {
    resolve('成功');
  } else {
    reject('失败');
  }
});

promise.then((value) => {
  // 处理成功的情况
  console.log('成功:', value);
}, (reason) => {
  // 处理失败的情况
  console.log('失败:', reason);
});

常见问题解答

  • 什么是 Promise 链?
    Promise 链是连续的 then() 调用,用于处理异步操作的结果。每个 then() 返回一个新的 Promise,该 Promise 依赖于前一个 Promise 的结果。

  • Promise 可以取消吗?
    原生 JavaScript Promise 无法取消。但是,你可以使用第三方库来创建可取消的 Promise。

  • 为什么我应该使用 Promise?
    Promise 使得异步编程更加容易和可读。它允许你编写顺序执行代码,即使存在异步操作。

  • 如何处理 Promise 错误?
    你可以使用 then() 的第二个参数来处理 Promise 错误。此参数是一个回调函数,它将接收 Promise 拒绝的原因。

  • 什么是 Promise.all() 和 Promise.race()?
    Promise.all() 返回一个 Promise,该 Promise 等待所有给定的 Promise 完成并返回一个包含所有结果的数组。Promise.race() 返回一个 Promise,该 Promise 等待第一个给定的 Promise 完成并返回其结果。

结论

了解 Promise 的工作原理并能够使用 TypeScript 实现它可以极大地增强你的 JavaScript 技能。Promise 为异步编程提供了强大的工具,它使你的代码更易于阅读、维护和可测试。通过练习和理解,你可以充分利用 Promise 的优势并编写更健壮、更高效的应用程序。