全网最详细最完善的Promise实现教程,带你彻底掌握Promise


前言

最近在学习各种 JS 函数的手写,看我这两天发布的文就知道了。

终于轮到 Promise 了,在网上搜寻一番之后发现功能大都不怎么完善,各种形形色色的 Promise 实现跟原生 Promise 的行为相比都不尽相同。

因此我决定自己实现一个 Promise,也算是深入学习了。

Promise A+

关于这个规范并不在本文的重点论述中,但是还是简单提一嘴,这个规范的内容主要就是 Promise 由三个状态组成:

  • Pending 待定
  • Fulfilled 兑现
  • Rejected 拒绝

并且后面两个状态都属于落定(Settled),唯独 Pending 属于未落定(Unsettled)。

Promise 只能由未落定状态转化为落定状态。

实现Promise的实例方法

正式开始 Promise 类的实现,我将一步步带你实现并了解其中的细节。

让我们先创建一个 Promise 的实现,类名就叫 PromiseImpl 吧。

class PromiseImpl {
  // Promise 的三个状态
  static PENDING = 0;
  static FULFILLED = 1;
  static REJECTED = 2;

  // 初始状态为 pending
  #status = PromiseImpl.PENDING;

  constructor() {}
}

Executor

Executor(执行器)是 Promise 构造函数中传入的回调函数,它用于初始化一个 Promise 对象,可以通过两个入参(resolve 和 reject)来决定兑现还是拒绝这个 Promise。

class PromiseImpl {
   // ...

   constructor(executor) {
      try {
         executor(this.#resolve.bind(this), this.#reject.bind(this));
      } catch (err) {
         // 当执行器抛出错误的时候,Promise 应该被拒绝
         this.#reject(err);
      }
   }

   #reject(reason) {}

   #resolve(value) {}
}

我们创建了 #resolve#reject 这两个用于兑现和拒绝的回调,并将其传入执行器中,供开发者决定何时落定。

Thenable

Promise 实例是一个 “Thenable” 的对象,所谓 “Thenable” 就是有 then() 函数。这样的对象可以使用 await 关键字转化为同步调用,具体涉及到 ES2017 中 await 语法糖的实现细节,再此不多做赘述。

返回一个新对象

通过以下代码,我们可以知道原生 Promise 的 .then() 方法实际上返回了一个 全新的 Promise 对象

const a = Promise.resolve(0);
const b = a.then((res) => res + 1);

console.log(a === b);   // => false

这就意味着我们不能通过 return this 的方法实现链式调用,而是需要在 then 方法中重新 new 一个 PromiseImpl 对象,因此可以给出以下实现。

class PromiseImpl {
   // ...

   // 保存 then 方法的回调和新 Promise 执行器的入参
   #onFulfilled;
   #onRejected;
   #thenResolve;
   #thenReject;

   then(onFulfilled, onRejected) {
      this.#onFulfilled = onFulfilled;
      this.#onRejected = onRejected;
      return new PromiseImpl((resolve, reject) => {
         this.#thenResolve = resolve;
         this.#thenReject = reject;
      });
   }
}

then 方法的 onFulfilledonRejected 两个参数可以理解为 调度器。调度器允许我们对传入的值做进一步的操作,并将其向后传递。

只不过此处 #onRejected 的行为并没有那么简单,我们会在后文做进一步讲解。

现在我们可以使用 then() 实现链式调用了:

new PromseImpl(/* ... */)
  .then(/* ... */)
  .then(/* ... */);

但是目前我们还无法让下一个 then() 在上一个 PromiseImpl 落定时被调用,因此我们需要完善 #resolve#reject 方法。

then回调的执行时机

我们知道,原生 Promise 构造函数中的执行器是一个同步回调,而 Promise.then() 方法中的回调则是异步回调,这部分异步回调被放在 微任务 中执行。

我们可以在当前 Promise 落定时将结果传递给下一个 Promise(放入微任务中执行)。

class PromiseImpl {
   // ...

   // 保存落定的值
   #settleValue;

   #resolve(value) {
      queueMicrotask(() => {
         let result;
         try {
            // 尝试通过调度器转化 value
            result = this.#onFulfilled ? this.#onFulfilled(value) : value;
         } catch (err) {
            // 如果调度器出现错误则直接落定为拒绝,并将错误向后传递
            this.#status = PromiseImpl.REJECTED;
            this.#settledValue = err;
            this.#thenReject?.(err);
            return;
         }
         // 更新 Promise 的状态为 fulfilled
         this.#status = PromiseImpl.FULFILLED;
         this.#settledValue = result;
         // 调用下一个 Promise 的落定回调
         this.#thenResolve?.(result);
      });
   }

   #reject(reason) {
      queueMicrotask(() => {
         // 尝试通过调度器转化 reason,发生错误则更新 reason 为新的错误
         if (this.#onRejected) {
            try {
               reason = this.#onRejected(reason);
            } catch (err) {
               reason = err;
            }
         }
         // 更新 Promise 的状态为 rejected
         this.#status = PromiseImpl.REJECTED;
         this.#settledValue = reason;
         // 调用下一个 Promise 的拒绝回调
         this.#thenReject?.(reason);
      });
   }

   // ...
}

像这样,在落定的时候向微任务队列推入新的任务,在这个任务中落定下一个 Promise 的值,这样我们就可以实现落定值的链式传递了。

但是有一个潜在的问题我们没有考虑到:如果落定的值是一个 PromiseImpl 对象,那该怎么办?

等待 PromiseImpl 类型的落定值

通过观察原生 Promise 的行为,我们可以得知如果返回的是一个 Promise 对象,那么会将 该 Promise 落定的值 传递下去,而不是直接传递 Promise 对象。

让我们先将调度结束后的操作提取封装为 process 方法:

class PromiseImpl {
   // ...

   // 保存落定的值
   #settleValue;

   #resolve(value) {
      queueMicrotask(() => {
         let result;
         try {
            result = this.#onFulfilled ? this.#onFulfilled(value) : value;
         } catch (err) {
            this.#status = PromiseImpl.REJECTED;
            this.#settledValue = err;
            this.#thenReject?.(err);
            return;
         }
         // 封装为 process 方法
         function process(result) {
            this.#status = PromiseImpl.FULFILLED;
            this.#settledValue = result;
            this.#thenResolve?.(result);
         }
         process(result);
      });
   }

   #reject(reason) {
      queueMicrotask(() => {
         if (this.#onRejected) {
            try {
               reason = this.#onRejected(reason);
            } catch (err) {
               reason = err;
            }
         }
         // 封装为 process 方法
         function process(reason) {
            this.#status = PromiseImpl.REJECTED;
            this.#settledValue = reason;
            this.#thenReject?.(reason);
         }
         process(reason);
      });
   }

   // ...
}

随后我们需要实现一个名为 #processPromiseResult 的方法,它会在传入的 PromiseImpl 对象兑现的时候调用 process 方法,在对象拒绝时调用 this.#reject()

然后,我们在刚刚封装的 process 方法中判断当前传入的值是否是一个 PromiseImpl 对象,如果是的话,调用 #processPromiseResult 递归地解析传入值,并停止继续处理。

class PromiseImpl {
   // ...

   // 等待当前 promise 落定再继续触发回调
   #processPromiseResult(promise, process) {
      promise.then(
         (res) => process(res),
         (err) => this.#reject(err)
      );
   }

   // 保存落定的值
   #settleValue;

   #resolve(value) {
      queueMicrotask(() => {
         let result;
         try {
            result = this.#onFulfilled ? this.#onFulfilled(value) : value;
         } catch (err) {
            this.#reject(err);
            return;
         }
         // 封装为 process 方法
         function process(result) {
            // 判断当前 result 是否是一个 Promise
            // 如果是的话等待落定再继续
            if (result instanceof PromiseImpl) {
               this.#processPromiseResult(result, process);
               return;
            }
            this.#status = PromiseImpl.FULFILLED;
            this.#settledValue = result;
            this.#thenResolve?.(result);
         }
         process(result);
      });
   }

   #reject(reason) {
      queueMicrotask(() => {
         if (this.#onRejected) {
            try {
               reason = this.#onRejected(reason);
            } catch (err) {
               reason = err;
            }
         }
         // 封装为 process 方法
         function process(reason) {
            // 判断当前 reason 是否是一个 Promise
            // 如果是的话等待落定再继续
            if (result instanceof PromiseImpl) {
               this.#processPromiseResult(result, process);
               return;
            }
            this.#status = PromiseImpl.REJECTED;
            this.#settledValue = reason;
            this.#thenReject?.(reason);
         }
         process(reason);
      });
   }

   // ...
}

观察到设置状态、设置落定值和落定下一个 Promise 这一系列将值向下传递的操作有所重复,我们将其可以提取出来做为 #passResolve#passReject 方法以简化代码。

class PromiseImpl {
   // ...

   // 对传递兑现值的操作进行封装
   #passResolve(result) {
      this.#status = PromiseImpl.FULFILLED;
      this.#settledValue = result;
      this.#thenResolve?.(result);
   }

   // 对传递拒绝值的操作进行封装
   #passReject(reason) {
      this.#status = PromiseImpl.REJECTED;
      this.#settledValue = reason;
      this.#thenReject?.(reason);
   }

   // 等待当前 promise 落定再继续触发回调
   #processPromiseResult(promise, process) {
      promise.then(
         (res) => process(res),
         (err) => this.#reject(err)
      );
   }

   // 保存落定的值
   #settleValue;

   #resolve(value) {
      queueMicrotask(() => {
         let result;
         try {
            result = this.#onFulfilled ? this.#onFulfilled(value) : value;
         } catch (err) {
            this.#passReject(err);
            return;
         }
         // 封装为 process 方法
         function process(result) {
            // 判断当前 result 是否是一个 Promise
            // 如果是的话等待落定再继续
            if (result instanceof PromiseImpl) {
               this.#processPromiseResult(result, process);
               return;
            }
            this.#passResolve(result);
         }
         process(result);
      });
   }

   #reject(reason) {
      queueMicrotask(() => {
         if (this.#onRejected) {
            try {
               reason = this.#onRejected(reason);
            } catch (err) {
               reason = err;
            }
         }
         // 封装为 process 方法
         function process(reason) {
            // 判断当前 reason 是否是一个 Promise
            // 如果是的话等待落定再继续
            if (result instanceof PromiseImpl) {
               this.#processPromiseResult(result, process);
               return;
            }
            this.#passReject(reason);
         }
         process(reason);
      });
   }

   // ...
}

这样我们就可以解析 PromiseImpl 类型的返回值了。

处理落定状态下的then

目前我们 then 方法的实现并未考虑落定状态下的情况,在已经落定的时候,then 返回的 PromiseImpl 对象应当 立即被落定#settleValue 的值。

class PromiseImpl {
  // ...

  then(onFulfilled, onRejected) {
    this.#onFulfilled = onFulfilled;
    this.#onRejected = onRejected;

    // 分三种情况进行处理
    if (this.#status === PromiseImpl.PENDING) {
      return new PromiseImpl((resolve, reject) => {
        this.#thenResolve = resolve;
        this.#thenReject = reject;
      });
    } else if (this.#status === PromiseImpl.FULFILLED) {
      this.#onFulfilled?.(this.#settledValue);
      return PromiseImpl.resolve(this.#settledValue); // PromiseImpl.resolve() 方法将在后文实现
    } else {
      this.#onRejected?.(this.#settledValue);
      return PromiseImpl.reject(this.#settledValue); // PromiseImpl.reject() 方法将在后文实现
    }
  }

  // ...
}

目前来说,我们的 “Thenable” 部分实现已经是比较完善的了,让我们继续实现 finallycatch 的部分吧。

捕获异常

当我们使用 await 等待一个 Promise 时,如果这个 Promise 发生了错误,那么此处会抛出一个异常。

你可能以为这部分需要我们自己来实现,实则不然。

经过观察,我发现当使用 await 去等待一个 PromiseImpl 对象的时候,它会自动对该对象调用一次 额外then 方法。结合先前手动实现 await 的经历,我认为 await 是通过这个额外的 then 去获取 PromiseImpl 对象最终的返回值的,而如果这个 then 方法的 onRejected 调度器被调用,那么 await 会通过调度器传入的 reason 参数去实例化一个 Error 对象并抛出。

await 的行为可以简单表示为以下代码:

const a = await promise;

// 这段代码有点类似于 👇
let a;
promise.then(
  (res) => a = res,
  (reason) => throw new Error(reason) // 抛出异常
);

如果链上抛出的异常被 onRejected 调度器处理了,就不会触发异常,这说明onRejected 调度器处理后的异常不会作为异常继续传递

由此我们可以得出一个结论:被 onRejected 调度器处理过的错误将会被转化为一个兑现的值并向下传递,而没有调度器处理错误的则会作为异常继续向下传递。

如图所示。

要想实现经 onRejected 调度器后转化为普通值继续向下传递,我们需要修改 #reject 回调中 process 方法的实现,使其在有 onRejected 调度器的时候停止继续传递异常。

class PromiseImpl {

  // ...

  #reject(reason) {
    queueMicrotask(() => {
      if (this.#onRejected) {
        try {
          reason = this.#onRejected(reason);
        } catch (err) {
          reason = err;
        }
      }

      const process = (reason) => {
        if (reason instanceof PromiseImpl) {
          this.#processPromiseResult(reason, process);
          return;
        }

        // 当存在 #onRejected 时要像 fulfuill 值一样处理
        if (this.#onRejected) {
          this.#passResolve(reason);
          return;
        }

        this.#status = PromiseImpl.REJECTED;
        this.#settledValue = reason;
        this.#thenReject?.(reason);
      };
      process(reason);
    });
  }

  // ...
}

这样一来,如果异常被调度器捕获,就不会作为异常继续传递,最后就不会导致外界抛出错误。

实现catch

通过前文的讨论,我们不难总结出 PromiseImpl.catch() 其实就是一个对 then 的封装方法,它直接调用 then 方法并传入异常处理函数。

class PromiseImpl {
    // ...

    // catch 实际上就是构造一个只有 onReject 调度器的 then 方法
    catch(callback) {
        return this.then(null, (reason) => {
            // 构造 Error 对象并传递给回调
            const err = new Error(reason);
            callback(err);
        });
    }

    // ...
}

正因为 PromiseImpl.catch()PromiseImpl.then() 方法传入了 onReject 调度器,当调用链上有 .catch() 方法的时候,错误会被传递给它处理。并且如上文展示的那样,.catch() 方法返回的将是一个 兑现 的 PromiseImpl 对象(因为错误已经被 onRejected 调度器处理过了)。

实现finally

finally 的实现原理也比较简单,它也可以看做是对 then 方法的封装,将回调作为 onFulfilledonRejected 调度器传入 then 方法。

class PromiseImpl {
    // ...

    // finally 实际上就是构造一个即有 onReject 又有 onFulfill 调度器的 then 方法
    finally(callback) {
        const cb = () => {
            callback();
            // 将传递过来的值继续向下传递
            return #settleValue;
        }
        return this.then(cb, cb);
    }

    // ...
}

我相信你多少也察觉到了一点,这样实现显然有问题:如果异常经过了 finallyonReject 调度器,就会被做为兑现值而不是异常值向下传递,这样就干扰了后续的异常处理。

要解决这个问题,我们首先要对 finally 中的回调 cb 打上其 “专属标签”,以供 #reject 方法识别和处理。

// 用 Symbol 值防止与其他属性名发生冲突
const __FINAL__ = Symbol();

class PromiseImpl {
    // ...

    finally(callback) {
        const cb = () => {
            callback();
            return #settleValue;
        }
        // 打上标签
        cb[__FINAL__] = true;
        return this.then(cb, cb);
    }

    // ...
}

然后在 #reject 方法中单独处理它。

class PromiseImpl {
   // ...

   #reject(reason) {
      queueMicrotask(() => {
         if (this.#onRejected) {
            try {
               reason = this.#onRejected(reason);
            } catch (err) {
               reason = err;
            }
         }

         const process = (reason) => {
            if (reason instanceof PromiseImpl) {
               this.#processPromiseResult(reason, process);
               return;
            }

            // 这里多了个条件,当调度器身上存在__FINAL__标签的时候
            // 不要做为兑现值向下传递
            if (this.#onRejected && !this.#onRejected[__FINAL__]) {
               this.#resolveNext(reason);
            } else {
               this.#rejectNext(reason);
            }
         };

         process(reason);
      });
   }

   // ...
}

这样一来,finally 就能正常工作了,至此,我们的 PromiseImpl 已经支持了原生的 Promise 所有的实例方法。

实现Promise的静态方法

Promise.resolve()

这个方法没什么好说的,比较简单。

class PromiseImpl {
   static resolve(value) {
      return new PromiseImpl((res) => res(value));
   }
}

Promise.reject()

同上。

class PromiseImpl {
   static reject(reason) {
      return new PromiseImpl((_, rej) => rej(reason));
   }
}

Promise.allSettled()

Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

初始化计数器为 Promise 的个数,在每个 Promise 落定的时候保存状态和结果并自减计数器,随后判断计数器是否等于 0,是则返回结果数组。

如果数组中元素不是 PromiseImpl 对象则会直接被兑现。

class PromiseImpl {
   static allSettled(promises) {
      return new PromiseImpl((resolve) => {
         let count = promises.length;
         const results = new Array(count);

         // 每一个 Promise 落定时都会调用
         const onSettled = (state, value, idx) => {
            const resultKey = state === 'fulfilled' ? 'value' : 'reason';
            results[idx] = {
               state,
               [resultKey]: value,
            };
            // 当 count 为 0 时全部落定,兑现结果数组
            --count === 0 && resolve(results);
         };

         promises.forEach((promise, idx) => {
            // 如果不是 PromiseImpl 则直接兑现
            if (!(promise instanceof PromiseImpl)) {
                onSettled('fulfilled', promise, idx);
                return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }
}

Promise.all()

Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

Promise.all() 的实现思路总体来说与 Promise.allSettled 相似,只不过在遇到第一个拒绝的时候就可以直接拒绝,只有在全部兑现的时候兑现。

class PromiseImpl {
   static all(promises) {
      return new PromiseImpl((resolve, reject) => {
         let count = promises.length;
         const results = new Array(count);

         // 每一个 Promise 落定时都会调用
         const onSettled = (state, value, idx) => {
            results[idx] = value;

            // 当全部兑现时兑现,任一个拒绝时拒绝
            if (--count === 0 || state === 'rejected') {
               status === 'fulfilled' ? resolve(results) : reject(value);
            }
         };

         promises.forEach((promise, idx) => {
            // 如果不是 PromiseImpl 则直接兑现
            if (!(promise instanceof PromiseImpl)) {
                onSettled('fulfilled', promise, idx);
                return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }
}

Promise.race()

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

onSettled 上做手脚使得其调用时立即返回结果即可。

class PromiseImpl {
   static race(promises) {
      return new PromiseImpl((resolve, reject) => {
         // 只要 onSettled 被触发就会马上落定
         const onSettled = (status, value) => {
            status === 'fulfilled' ? resolve(value) : reject(value);
         };

         promises.forEach((promise, idx) => {
            if (!(promise instanceof PromiseImpl)) {
               onSettled('fulfilled', promise, idx);
               return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }
}

Promise.any()

Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

实现比较简单,不多赘述。

class PromiseImpl {
   static any(promises) {
      return new PromiseImpl((resolve, reject) => {
         let count = promises.length;
         const reasons = new Array(count);

         // 只要任意一个兑现就会立刻返回,否则当所有拒绝之后拒绝为一个理由数组
         const onSettled = (status, value, idx) => {
            if (status === 'fulfilled') {
               resolve(value);
            } else {
               reasons[idx] = value;
               --count === 0 && reject(reasons);
            }
         };

         promises.forEach((promise, idx) => {
            if (!(promise instanceof PromiseImpl)) {
               onSettled('fulfilled', promise, idx);
               return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }
}

以上就是所有 Promise 静态方法的实现,只不过此处没有实现一些比较新的 Promise 方法,我决定留到日后专门写文记录。

完整代码

const __FINAL__ = Symbol();

class PromiseImpl {
   static PENDING = 0;
   static FULFILLED = 1;
   static REJECTED = 2;

   #status = PromiseImpl.PENDING;
   #settledValue = undefined;
   #onFulfilled;
   #onRejected;
   #thenResolve;
   #thenReject;

   constructor(executor) {
      try {
         executor(this.#resolve.bind(this), this.#reject.bind(this));
      } catch (err) {
         this.#reject(err);
      }
   }

   /// 私有方法

   #processPromiseResult(promise, callback) {
      promise.then(
         (result) => callback(result),
         (reason) => this.#rejectNext(reason)
      );
   }

   #resolve(value) {
      queueMicrotask(() => {
         let result;
         try {
            result = this.#onFulfilled ? this.#onFulfilled(value) : value;
         } catch (err) {
            this.#rejectNext(err);
            return;
         }

         const process = (result) => {
            if (result instanceof PromiseImpl) {
               this.#processPromiseResult(result, process);
               return;
            }

            this.#resolveNext(result);
         };

         process(result);
      });
   }

   #reject(reason) {
      queueMicrotask(() => {
         if (this.#onRejected) {
            try {
               reason = this.#onRejected(reason);
            } catch (err) {
               reason = err;
            }
         }

         const process = (reason) => {
            if (reason instanceof PromiseImpl) {
               this.#processPromiseResult(reason, process);
               return;
            }

            if (this.#onRejected && !this.#onRejected[__FINAL__]) {
               this.#resolveNext(reason);
            } else {
               this.#rejectNext(reason);
            }
         };

         process(reason);
      });
   }

   #rejectNext(reason) {
      this.#status = PromiseImpl.REJECTED;
      this.#settledValue = reason;
      this.#thenReject?.(reason);
   }

   #resolveNext(value) {
      this.#status = PromiseImpl.FULFILLED;
      this.#settledValue = value;
      this.#thenResolve?.(value);
   }

   /// 成员方法

   then(onFulfilled, onRejected) {
      this.#onFulfilled = onFulfilled;
      this.#onRejected = onRejected;

      if (this.#status === PromiseImpl.PENDING) {
         return new PromiseImpl((resolve, reject) => {
            this.#thenResolve = resolve;
            this.#thenReject = reject;
         });
      } else if (this.#status === PromiseImpl.FULFILLED) {
         this.#onFulfilled?.(this.#settledValue);
         return PromiseImpl.resolve(this.#settledValue);
      } else {
         this.#onRejected?.(this.#settledValue);
         return PromiseImpl.reject(this.#settledValue);
      }
   }

   catch(callback) {
      return this.then(null, (reason) => {
         const err = new Error(reason);
         callback(err);
      });
   }

   finally(callback) {
      const cb = (val) => {
         callback();
         return val;
      };
      cb[__FINAL__] = true;
      return this.then(cb, cb);
   }

   /// 静态方法

   static resolve(value) {
      return new PromiseImpl((res) => res(value));
   }

   static reject(reason) {
      return new PromiseImpl((_, rej) => rej(reason));
   }

   static all(promises) {
      return new PromiseImpl((resolve, reject) => {
         let count = promises.length;
         const results = new Array(count);

         const onSettled = (status, value, idx) => {
            results[idx] = value;

            if (--count === 0 || status === 'rejected') {
               status === 'fulfilled' ? resolve(results) : reject(value);
            }
         };

         promises.forEach((promise, idx) => {
            if (!(promise instanceof PromiseImpl)) {
               onSettled('fulfilled', promise, idx);
               return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }

   static allSettled(promises) {
      return new PromiseImpl((resolve) => {
         let count = promises.length;
         const results = new Array(count);

         const onSettled = (status, value, idx) => {
            const resultKey = status === 'fulfilled' ? 'value' : 'reason';
            results[idx] = {
               status,
               [resultKey]: value,
            };
            --count === 0 && resolve(results);
         };

         promises.forEach((promise, idx) => {
            if (!(promise instanceof PromiseImpl)) {
               onSettled('fulfilled', promise, idx);
               return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }

   static race(promises) {
      return new PromiseImpl((resolve, reject) => {
         const onSettled = (status, value) => {
            status === 'fulfilled' ? resolve(value) : reject(value);
         };

         promises.forEach((promise, idx) => {
            if (!(promise instanceof PromiseImpl)) {
               onSettled('fulfilled', promise, idx);
               return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }

   static any(promises) {
      return new PromiseImpl((resolve, reject) => {
         let count = promises.length;
         const reasons = new Array(count);

         const onSettled = (status, value, idx) => {
            if (status === 'fulfilled') {
               resolve(value);
            } else {
               reasons[idx] = value;
               --count === 0 && reject(reasons);
            }
         };

         promises.forEach((promise, idx) => {
            if (!(promise instanceof PromiseImpl)) {
               onSettled('fulfilled', promise, idx);
               return;
            }
            promise.then(
               (result) => onSettled('fulfilled', result, idx),
               (reason) => onSettled('rejected', reason, idx)
            );
         });
      });
   }
}