手写Promise的常用方法

88 阅读2分钟

Promise 并发方法

在现代 JavaScript 中,处理异步操作时,Promise 是一种常见的工具。在处理多个异步操作时,Promise 提供了几种并发方法:Promise.allPromise.allSettledPromise.racePromise.any。这些方法都接收一个 Promise 数组,返回一个新的 Promise。下面我们将依次介绍这些方法的用法及其实现。


1. Promise.all

Promise.all 方法返回一个新的 Promise,当所有输入的 Promise 都被 fulfilled(兑现)时,返回的 Promise 也将被 fulfilled,并返回一个包含所有兑现值的数组。如果输入的任何 Promiserejected(拒绝),则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

实现

Promise.myAll = (promises) => {
  return new Promise((resolve, reject) => {
    const results = Array(promises.length);
    let completedPromises = 0;
    
    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then((data) => {
          results[index] = data;
          completedPromises++;
          
          if (completedPromises === promises.length) {
            resolve(results);
          }
        })
        .catch(err => {
          reject(err);
        });
    });
  });
}

关键点:我们使用一个 completedPromises 变量来跟踪已完成的 Promise 数量。当 completedPromises 数量等于输入的 Promise 数组长度时,我们调用 resolve 来返回结果数组。


2. Promise.allSettled

Promise.allSettled 方法返回一个新的 Promise,当所有输入的 Promise 都已 settled(即无论是 fulfilled 还是 rejected)时,返回的 Promise 将被 fulfilled,并带有描述每个 Promise 结果的对象数组。

实现

Promise.myAllSettled = (promises) => {
  return new Promise((resolve) => {
    const res = Array(promises.length);
    let completedPromises = 0;

    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then(data => {
          res[index] = { status: 'fulfilled', value: data };
        })
        .catch(error => {
          res[index] = { status: 'rejected', reason: error };
        })
        .finally(() => {
          completedPromises++;
          
          if (completedPromises === promises.length) {
            resolve(res);
          }
        });
    });
  });
}

关键点Promise.allSettled 总是返回一个 fulfilled 状态的 Promise,无论输入的 Promisefulfilled 还是 rejected,都将其结果记录在结果数组中。


3. Promise.race

Promise.race 方法返回一个新的 Promise,当数组中任意一个 Promise 变为 fulfilledrejected 时,返回的 Promise 也将变为相同状态。换句话说,它返回第一个 settled 的 Promise 的结果。

实现

Promise.myRace = (promises) => {
  return new Promise((resolve, reject) => {
    promises.forEach(promise => {
      Promise.resolve(promise)
        .then(resolve)
        .catch(reject);
    });
  });
}

关键点Promise.race 会立即返回第一个被 fulfilledrejectedPromise,这使得它非常适合处理竞态情况,例如多个异步操作中,只关心最快返回的结果。


4. Promise.any

Promise.any 方法返回一个新的 Promise,只要数组中任意一个 Promise 成功(fulfilled),返回的 Promise 就会被 fulfilled,并带有该成功值。如果所有 Promise 都被拒绝(rejected),则返回的 Promise 将被 rejected,并带有一个 AggregateError,其中包含所有错误信息。

实现

Promise.myAny = (promises) => {
  return new Promise((resolve, reject) => {
    let rejectCount = 0;
    const errors = [];
    
    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then(resolve)
        .catch(err => {
          errors[index] = err;
          rejectCount++;
          
          if (rejectCount === promises.length) {
            reject(new AggregateError(errors, 'All promises were rejected'));
          }
        });
    });
  });
}

关键点Promise.any 的特点是只要有一个 Promise 成功就会返回成功的结果,而只有所有 Promise 都失败时,才会返回一个 AggregateError


总结

通过使用 Promise.allPromise.allSettledPromise.racePromise.any,我们可以更灵活地处理 JavaScript 中的异步操作。这些方法为不同的并发场景提供了不同的控制策略,使得在编写复杂异步逻辑时,代码更简洁、更具可读性。理解并正确使用这些方法,是编写高效、可维护异步代码的关键。