【JS Promise】手写实现 promise.all 和promise.race 方法

promise.all:只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且 reject 的是第一个抛出的错误信息。若没有失败的,则最终返回一个包含所有成功结果的数组

promise.race:一旦迭代器中的某个 promise resolved或rejected,返回的 promise 就会resolved或rejected。

在实现之前,先来体验一下promise.allpromise.race的使用:

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(Promise.resolve(2));
const p3 = Promise.resolve(Promise.reject(3));
const p4 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(4);
  }, 1000);
});

Promise.all([p4, p1, p2]).then(
  (value) => {
    console.log('res1 value:', value);
  },
  (reason) => {
    console.log('res1 reason:', reason);
  },
);

Promise.all([p1, p2, p3, p4]).then(
  (value) => {
    console.log('res2 value:', value);
  },
  (reason) => {
    console.log('res2 reason:', reason);
  },
);

Promise.race([p4, p1, p3, p2]).then(
  (value) => {
    console.log('res3 value:', value);
  },
  (reason) => {
    console.log('res3 reason:', reason);
  },
);

/* 执行结果
res2 reason: 3
res3 value: 1
res1 value: [ 4, 1, 2 ]
*/

1. promise.all实现

实现的大致思路如下:

  • 返回一个新的promise对象
  • 遍历任务数组
    • 若前任务成功,则将成功的结果暂时存到对应的结果数组中的位置
    • 若失败,则直接reject即可
  • 当成功的任务数和总任务数一致时,将结果数组resolve出去
const pAll = (promises) => {

  // 保存所有成功结果的数组
  const values = [];
  // 成功的次数
  let successCount = 0;

  // 返回一个promise对象
  return new Promise((resolve, reject) => {

    // 遍历异步任务数组
    promises.forEach((p, index) => {

      /**
       * 这里用 Promise.resolve()包装一下p是考虑promises中的值有可能不是promise对象,
       * 例如普通的值 pAll([p1, p2, 2, 'hello'])
       */
      Promise.resolve(p).then(
        (value) => {

          /**
           * 注意这里不要用 values.push(value) 这种方式来将成功的值放到数组中
           * 由于promises数组中的异步任务并不一定是按顺序完成的
           * 应该使用 values[index] = value 这种方式
           */
          values[index] = value;
          successCount += 1;
          
          // 当成功的次数等于promises异步任务数组的长度时,将最终的结果resolve出去
          if (successCount === promises.length) {
            resolve(values);
          }
        },
        (reason) => {

          // 当遇到一个异步任务失败的时候,直接reject即可,后续的任务再失败就不用考虑了
          reject(reason);
        },
      );
    });
  });
};

可以测试一下我们实现的代码:

pAll([p4, p1, p2]).then(
  (value) => {
    console.log('res value:', value);
  },
  (reason) => {
    console.log('res reason:', reason);
  },
);


/* 执行结果
res value: [ 4, 1, 2 ]
*/

2. promise.race实现

promise.race的实现相对来说就更简单一些了。

const pRace = (promises) => {
  return new Promise((resolve, reject) => {
    promises.forEach((p) => {
      p.then(
        (value) => {
          resolve(p);
        },
        (reason) => {
          reject(reason);
        },
      );
    });
  });
};

同样测试一下代码:

pRace([p4, p1, p3, p2]).then(
  (value) => {
    console.log('value:', value);
  },
  (reason) => {
    console.log('reason:', reason);
  },
);

/* 执行结果
value: 1
*/

你可能感兴趣的:(大前端,javascript,前端,开发语言)