巧用 `Promise.all` 完成函数:有一个 Promise 被 resolve 全部函数就被 resolve

挪用分布式效劳接口时经常会碰到如许的题目:接口方供应多个 IP 供用户挪用,只需有一个返回胜利就算胜利。

关于如许的题目,一个比较简朴的计划是顺次挪用各个接口,假如前一个接口未胜利返回再挪用第二个接口。如许做的优点是关于效劳器资本斲丧比较小,但关于用户来讲效力异常低下。想象挪用第一个接口经由 20 秒超时失足才挪用第二个接口,假如第二个接口又是 20 秒超时,用户就已等待了 40 秒。用户的等待时间按线性增进,如许的效果时不可接收的。

好的解决计划是同时并发挪用一切接口,有些同砚可能会想到 Promise.race。然则请注意:Promise.race 不是比及有一个 Promise 被 resolve 时返回,而是只需有一个 Promise 被 fulfill 时就会返回,不管这个 Promise 是 resolve 照样 reject。

我就碰到过类似题目,固然也被 Promise.race 坑害了一回。上谷歌搜到了老外这篇博文:Promise me you won’t use Promise.race。博文中细致探讨了这个题目,并用 Promise.race 完成了一个解决计划:

Promise.properRace = function properRace(promises) {
  if (promises.length < 1) {
    return Promise.reject('Can\'t start a race without promises!');
  }

  // There is no way to know which promise is rejected.
  // So we map it to a new promise to return the index when it fails
  const indexPromises = promises.map((p, index) => p.catch(e => {
    console.debug('Promise rejected in `properRace`: ' + e);
    return Promise.reject(index);
  }));

  return Promise.race(indexPromises).catch(index => {
    // The promise has rejected, remove it from the list of promises and just continue the race.
    promises.splice(index, 1)[0].catch(() => { /* eat this */ });
    return promises.length ? properRace(promises) : Promise.reject('All promises rejected');
  });
};

虽然略显庞杂,但要领确切很奇妙,我早期就使用了这类要领。近来回过头来倏忽想到:properRace 的需求是只需有一个被 resolve 返回的 Promise 就被 resolve;JavaScript 虽然没有供应如许的函数,然则供应了别的一个很类似的函数:只需有一个被 reject 返回的 Promise 就被 reject。

这个函数我们很经常使用,就是:Promise.all

想到这一层,那末用它来完成 properRace 就很简朴了:把传入的 Promise 数组状况正反对换就好了。效果以下:

Promise.properRace = function properRace(promises) {
  const resolve = Promise.resolve.bind(Promise);
  const reject = Promise.reject.bind(Promise);
  return Promise.all(promises.map(x => x.then(reject, resolve)))
    .then(reject, resolve);
}

2019年7月更新

此要领已被规范化为 Promise.any

    原文作者:CarterLi
    原文地址: https://segmentfault.com/a/1190000013125262
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞