Skip to content

深入解析 Promise A+ 规范

随着 JavaScript 异步编程的广泛应用,Promise成为了处理异步操作的一种强大工具。Promise A+规范是Promise的标准制定规范,确保不同环境下的Promise实现行为一致。在本文中,我们将深入解析Promise A+规范,并通过手写简单的Promise实现来更好地理解其内部工作原理。

Promise A+规范概述

Promise A+规范定义了Promise的行为、方法以及与其他JavaScript特性的交互。该规范主要包括以下几个核心要素:

  1. Promise状态: Promise有三种状态,分别是pending(进行中)、fulfilled(已成功)和rejected(已失败)。Promise的状态一旦从pending转变为fulfilled或rejected就不可再改变。

  2. Promise方法: Promise提供了 then 方法,用于注册在Promise状态改变时的回调函数。then 方法接受两个参数,一个是在Promise成功时执行的回调函数,另一个是在Promise失败时执行的回调函数。

  3. Promise解决过程: Promise A+规范明确定义了一个Promise的解决过程,用于处理Promise的状态转变和回调的执行。

  4. Promise链式调用: then 方法可以链式调用,即一个 then 方法的返回值仍然是一个Promise,使得可以形成Promise调用链。

Promise与Promise A+规范的关系

Promise A+规范定义了Promise的行为和规则,而实际的Promise实现需要遵循这些规范,确保在不同的JavaScript环境中,Promise的行为保持一致。ES6引入的Promise就是基于Promise A+规范的一种实现。

在ES6之前,很多库和框架也实现了Promise,但由于缺乏标准,它们之间的行为可能存在差异。Promise A+规范的制定解决了这个问题,成为了各种Promise实现的基准。

手写Promise实现

为了更好地理解Promise A+规范,让我们尝试手写一个简单的Promise实现:

javascript
class MyPromise {
  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(callback => callback());
      }
    };

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

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

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

    const newPromise = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onFulfilled(this.value);
              resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onRejected(this.reason);
              resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return newPromise;
  }
}

function resolvePromise(newPromise, result, resolve, reject) {
  if (newPromise === result) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  if (result instanceof MyPromise) {
    result.then(
      value => resolve(value),
      reason => reject(reason)
    );
  } else {
    resolve(result);
  }
}
class MyPromise {
  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(callback => callback());
      }
    };

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

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

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

    const newPromise = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onFulfilled(this.value);
              resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onRejected(this.reason);
              resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return newPromise;
  }
}

function resolvePromise(newPromise, result, resolve, reject) {
  if (newPromise === result) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  if (result instanceof MyPromise) {
    result.then(
      value => resolve(value),
      reason => reject(reason)
    );
  } else {
    resolve(result);
  }
}

这是一个简化版的Promise实现,仅包含基本的异步处理和链式调用。在实际应用中,需要处理更多细节和边界情况,但这个简单实现足以帮助我们理解Promise A+规范的基本原理。

上次更新于: