【手写 Promise 源码】第十三篇 - Promise.allsettled 和 Promise.any 的实现

992 阅读3分钟

一,前言

上一篇,主要实现了 Promise 静态 API(类方法):Promise.race,主要涉及以下几个点:

  • 测试原生 Promise.race 的使用;
  • Promise.race 的功能与特性分析;
  • Promise.race 的源码实现、执行分析、功能测试;

本篇,继续实现 Promise 静态 API:Promise.allSettledPromise.any


二,Promise.allsettled 简介

1,API 介绍

MDN 参考资料

image.png

Promise.allsettled

  • 批处理 promise,返回 promise;
  • 存在失败结果也会拿到全部执行结果,不会走 catch;
  • 解决了 Promise.all 不能拿到失败执行结果的问题;

2,原生 Promise.allsettled 功能测试

// p1:立即成功
const p1 = Promise.resolve("p1_success");
// p2:2 秒后成功
const p2 = new Promise((resolve, reject) => setTimeout(resolve, 2000, 'p2_success'));
// p3:1 秒后失败
const p3 = new Promise((resolve, reject) => setTimeout(reject, 1000, 'p3_success'));

Promise.allSettled([p1, p2, p3, 1]).
  then((results) => results.forEach((result) => console.log(result)));
  
// 执行结果:2 秒后全部执行完成
{ status: 'fulfilled', value: 'p1_success' }
{ status: 'fulfilled', value: 'p2_success' }
{ status: 'rejected', reason: 'p3_success' }
{ status: 'fulfilled', value: 1 }
  • allSettled 现象: 全部执行完成,返回执行结果数组(下标与按执行顺序一致)

三,Promise.allsettled 实现

1,原理分析

  • Promise.allsettled:入参是一个 promise 集合;返回一个 Promise 实例; Promise.allsettled 内部 return new Promise(...)
  • 所有 promise 都会被执行完,并且按照执行顺序返回执行结果; Promise.allsettled 不会走 reject,按执行顺序全部收集到数组后 resolve 返回即可;

2,代码实现

// allSettle:全部执行完成后,返回全部执行结果(成功+失败)
static allSettled(promises) {
  const result = new Array(promises.length); // 记录执行的结果:用于返回直接结果
  let times = 0;     // 记录执行完成的次数:判断是否完成
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      if (p && typeof p.then === 'function') {
        p.then((data) => {
          result[i] = { status: 'fulfilled', value: data }
          times++;
          if (times === promises.length) {
            resolve(result);
          }
        }).catch(err => {
          result[i] = { status: 'rejected', reason: err }
          times++;
          if (times === promises.length) {
            resolve(result);
          }
        })
      } else { // 普通值,加入
        result[i] = { status: 'fulfilled', value: p }
        times++;
        if (times === promises.length) {
          resolve(result);
        }
      }
    }
  })
}

四,Promise.any 简介

1,API 介绍

MDN 参考资料

image.png

Promise.any

  • 批处理 promise,返回 promise;
  • 返回第一个成功结果,全部失败才返回失败;
  • 解决了 Promise.race 只能拿到第一个执行完成(不管成功/失败)的结果;

五,Promise.any 实现

1,原理分析

  • Promise.any:入参是一个 promise 集合;返回一个 Promise 实例; Promise.any 内部 return new Promise(...)
  • 执行所有 promise,使用最先返回的成功结果;全部失败才判定为失败; p.then("谁先成功就返回谁","失败了先存起来,都失败了才返回")

2,代码实现

// any:一个成功就成功,全部失败才失败
static any(promises) {
  const rejectedArr = []; // 记录失败的结果
  let rejectedTimes = 0;  // 记录失败的次数
  return new Promise((resolve, reject) => {
    if(promises == null || promises.length == 0){
      reject("无效的 any");
    }
    for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      // 处理 promise
      if (p && typeof p.then === 'function') {
        p.then((data) => {
          resolve(data) // 使用最先成功的结果
        }, (err) => { // 如果失败了,保存错误信息;当全失败时,any 才失败
          rejectedArr[i] = err;
          rejectedTimes++;
          if (rejectedTimes === promises.length) {
            reject(rejectedArr);
          }
        })
      }else{// 处理普通值,直接成功
        resolve(p)
      }
    }
  })
}

3,功能测试

const pErr = new Promise((resolve, reject) => {
  setTimeout(reject, 1000, "失败了");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 5000, "慢的成功");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, "快的成功");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log("Promise.any 成功", value);
}).catch(err =>{
  console.log("Promise.any 失败", err);
})

// 执行结果:
2 秒后返回:"Promise.any 成功 快的成功"5 秒后执行完成;

六,结尾

本篇,主要实现 Promise 静态 API:Promise.allSettledPromise.any,主要涉及以下几个点:

  • 测试原生 Promise.allsettled 的使用;
  • Promise.allsettled 原理分析、源码实现、功能测试;
  • Promise.any 原理分析、源码实现、功能测试;

下一篇,实现一个 promisify 工具函数;


维护记录

  • 20211120
    • 修改结尾部分,更新文章摘要