返回

用最简单的实践,实现 Promises/A+ 规范的 Promise

前端

概述:Promises 的作用与基本概念
Promises/A+ 是一个规范,它定义了 JavaScript 异步编程中 Promise 的行为。Promise 是一个对象,它表示一个异步操作的最终完成或失败及其结果值。使用 Promise 可以使异步编程更加容易和可读。Promises/A+ 规范定义了 Promise 的基本概念,包括:

  • 状态: Promise 有三个状态:pending(等待)、fulfilled(已完成)和 rejected(已拒绝)。
  • 值: Promise 可以有一个值,它可以是任何类型的数据。
  • 回调: Promise 可以注册回调函数,当 Promise 的状态改变时,这些回调函数会被调用。
  • 链式调用: Promise 可以被链式调用,这意味着可以将多个 Promise 连接起来,以便在一个 Promise 完成后自动执行下一个 Promise。

Promises/A+ 规范的要求
Promises/A+ 规范定义了 Promise 必须满足的一些要求,这些要求包括:

  • Promise 必须有一个 then 方法: then 方法允许注册回调函数,当 Promise 的状态改变时,这些回调函数会被调用。
  • Promise 的状态只能从 pending 变成 fulfilled 或 rejected: Promise 的状态一旦改变,就不可再改变。
  • Promise 的值只能被设置一次: Promise 的值一旦被设置,就不可再改变。
  • Promise 的回调函数必须异步执行: Promise 的回调函数不能在 Promise 的构造函数中执行。
  • Promise 必须支持链式调用: Promise 可以被链式调用,这意味着可以将多个 Promise 连接起来,以便在一个 Promise 完成后自动执行下一个 Promise。

实现 Promises/A+ 规范的 Promise
现在,让我们一步步实现一个符合 Promises/A+ 规范的 Promise。首先,我们需要定义 Promise 的状态:

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

接下来,我们需要定义 Promise 的构造函数:

function Promise(executor) {
  this.state = PENDING;
  this.value = undefined;
  this.reason = undefined;
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];

  const resolve = (value) => {
    if (this.state !== PENDING) return;

    this.state = FULFILLED;
    this.value = value;
    this.onFulfilledCallbacks.forEach(callback => callback(value));
  };

  const reject = (reason) => {
    if (this.state !== PENDING) return;

    this.state = REJECTED;
    this.reason = reason;
    this.onRejectedCallbacks.forEach(callback => callback(reason));
  };

  executor(resolve, reject);
}

Promise 的构造函数接受一个 executor 函数作为参数。executor 函数有两个参数:resolve 和 reject。resolve 函数用于将 Promise 的状态从 pending 变成 fulfilled,reject 函数用于将 Promise 的状态从 pending 变成 rejected。

接下来,我们需要定义 Promise 的 then 方法:

Promise.prototype.then = function(onFulfilled, onRejected) {
  if (typeof onFulfilled !== 'function') {
    onFulfilled = value => value;
  }

  if (typeof onRejected !== 'function') {
    onRejected = reason => { throw reason; };
  }

  const promise2 = new Promise((resolve, reject) => {
    if (this.state === FULFILLED) {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value);
          resolvePromise(promise2, x);
        } catch (error) {
          reject(error);
        }
      }, 0);
    } else if (this.state === REJECTED) {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason);
          resolvePromise(promise2, x);
        } catch (error) {
          reject(error);
        }
      }, 0);
    } else {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });

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

  return promise2;
};

Promise 的 then 方法接受两个参数:onFulfilled 和 onRejected。onFulfilled 函数用于处理 Promise 的值,onRejected 函数用于处理 Promise 的原因。then 方法返回一个新的 Promise,这个新的 Promise 的状态取决于 onFulfilled 和 onRejected 函数的返回值。

最后,我们需要定义一个 resolvePromise 函数:

function resolvePromise(promise, x) {
  if (promise === x) {
    throw new TypeError('Chaining cycle detected');
  }

  if (x instanceof Promise) {
    x.then(
      value => resolvePromise(promise, value),
      reason => reject(reason)
    );
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;
      if (typeof then === 'function') {
        let called = false;
        try {
          then.call(
            x,
            value => {
              if (called) return;
              called = true;
              resolvePromise(promise, value);
            },
            reason => {
              if (called) return;
              called = true;
              reject(reason);
            }
          );
        } catch (error) {
          if (called) return;
          called = true;
          reject(error);
        }
      } else {
        resolve(x);