# 10. Promise的 all/any/race/allSettled 方法的区别

在实现 Promise.all 方法之前,我们首先要知道 Promise.all 的功能和特点,因为在清楚了 Promise.all 功能和特点的情况下,我们才能进一步去写实现。

# 1. 返回的promise状态改变时机不同

  • all
    当所有的输入promise实例的状态都改变为fulfilled状态,新的promise实例才是fulfilled状态,返回所有输入promise实例的resolve value数组; 如果有一个promise实例的状态是rejected,则新的promise实例的状态就是rejected,返回第一个promise reject的reason

  • allSettled
    返回所有promise实例执行的数组,格式如下:

[
  {status: "fulfilled", value: 1},
  {status: "rejected", reason: "error"},
  {status: "rejected", reason: 2},
]
  • any
    返回promise数组中最先变成fulfilled实例的value,如果所有输入的promise实例的状态都是rejected, 返回all promise were rejected

  • race
    返回最先执行结束的promise的value或者reason,不论状态是rejected还是fulfilled

# 2. 返回的promise实例的终值或者拒因不同

  • all 方法返回的promise实例终值是一个数组,数组的成员是所有输入的promise实例的终值,并将会按照参数内的promise顺序排列,而不是promise的完成顺序;拒因是输入的promise实例钟第一个状态变为rejected的拒因。
  • allSettled 方法返回的promise实例终值也是一个数组,顺序同promise的输入顺序一致,其中每个成员在输入 promise 为 resolved 状态时为 {status:'fulfilled', value:同一个终值},rejected 状态时为 {status:'rejected', reason:同一个拒因}。

# 3. 参数为空迭代对象时,返回值不同

  • all 方法会同步的返回一个已完成状态的promise, 终值值一个空数组
  • allSettled 方法和all表现形式相同
  • any 方法会同步的返回一个失败状态的promise,拒因是一个AggregateError对象
  • race 方法返回一个pending状态的promise

测试:

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 500)
  })

  const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('p2 error')
    }, 1000)
  })

  const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('p2 error')
    }, 1500)
  })

  Promise.all([p1, p2, p3])
    .then(res => console.log('then', res))
    .catch(err => console.log('catch', err))//catch p2 error

  Promise.race([p1, p2, p3])
    .then(res => console.log('then', res))//then 1
    .catch(err => console.log('catch', err))

  Promise.allSettled([p1, p2, p3])
    .then(res => console.log('then', res))//数组
    .catch(err => console.log('catch', err))

  Promise.any([p1, p2, p3])
    .then(res => console.log('then', res))//then 1
    .catch(err => console.log('catch', err))

  Promise.all([])
    .then(res => console.log('then', res))//[]
    .catch(err => console.log('catch', err))
  Promise.any([])
    .then(res => console.log('then', res))
    .catch(err => console.log('catch', err))//AggregateError: All promises were rejected
  Promise.allSettled([])
    .then(res => console.log('then', res))//[]
    .catch(err => console.log('catch', err))
  Promise.race([])//pengding状态不输出结果
    .then(res => console.log('then', res))
    .catch(err => console.log('catch', err))

# 手写实现

  1. promise.all
function _all (promises) {
  // count 计数器,与len比较,判断是否所有的promise都已经成功了;
  // result 用于存放成功的结果。
  let count=0, len=promises.length, result=[];
  return new Promise((resolve, reject) => {
    // 依次判断传入的promise实例是否成功
    for(let p of promises) {
      Promise.resolve(p).then(res => {
        result[count] = res;
        count++;
        if(count === len) {
          //相等,说明所有的promise实例都成功了, 才可以resolve结果
          resolve(result);
        }
      }).catch(err => reject(err)); //只要有一个失败了就reject出去
    }
  })
}
  1. promise.allSettled
function _allSettled (promises) {
  let result=[],len=promises.length; count=0;
  return new Promise((resolve, reject) => {
    for(let p of promises) {
      Promise.resolve(p).then(res => {
        result[count] ={
          status:'fulfilled',
          result:res
        }
        count++;
        if(count === len) {
          resolve(result)
        }
      }).catch(err => {
        result[count] ={
          status:'rejected',
          result:err
        }
        count++;
        if(count === len) {
          reject(result);
        }
      })
    }
  })
}
  1. promise.any
function _any (promises) {
  let result =[],len=promises.length, count=0;
  return new Promise((resolve, reject) => {
    for(let p of promises) {
      Promise.resolve(p).then(res => {
        resolve(res);
      }).catch(err => {
        result[count]=err;
        count++;
        if(count===len){
          reject(result)
        }
      })
    }
  })
} 
  1. promise.race
function _race (promises) {
  return new Promise((resolve, reject) => {
    for(let p of promises) {
      Promise.resolve(p).then(res => {
        resolve(res)
      }).catch(err=> reject(err))
    }
  })
}