资讯专栏INFORMATION COLUMN

巧用 `Promise.all` 实现函数:有一个 Promise 被 resolve 整个函数就被

genefy / 3168人阅读

摘要:调用分布式服务接口时经常会遇到这样的问题接口方提供多个供用户调用,只要有一个返回成功就算成功。但是请注意不是等到有一个被时返回,而是只要有一个被时就会返回,不论这个是还是。

调用分布式服务接口时经常会遇到这样的问题:接口方提供多个 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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107218.html

相关文章

  • JavaScript Promise API

    摘要:我们使用关键字和提供的和回调函数来创建新的根据异步任务的返回结果,开发者可以在回调函数体的内部手动调用或者。第一个方法的回调函数接收方法里的值当被时,会调用回调方法。如果被,而方法在之后,那回调函数永远不会被执行。 尽管同步代码易于追踪和调试,但异步代码普遍在性能和灵活性上更具优势。Why hold up the show when you can trigger numerous r...

    peixn 评论0 收藏0
  • 从0到1实现Promise

    摘要:通过或者拿到方法回调函数的返回值,然后调用,将新增的的和传入到中。打印结果实现方法接收一个包含多个的数组,当有一个为状态时,整个大的为,并执行回调函数。 前言 Promise大家一定都不陌生了,JavaScript异步流程从最初的Callback,到Promise,到Generator,再到目前使用最多的Async/Await(如果对于这些不熟悉的可以参考我另一篇文章《JavaScri...

    EddieChan 评论0 收藏0
  • 马蹄疾 | 详解 JavaScript 异步机制及发展历程(万字长文)

    摘要:本文从入手,系统的回顾的异步机制及发展历程。需要提醒的是,文本没有讨论的异步机制。这就是之前提到的事件触发线程。其实无论是请求还是定时器还是事件,我们都可以统称它们为事件。第二阶段,引擎线程专注于处理事件。将外元素的事件回调放入调用栈。 functionshowImg(url){ varframeid=frameimg+Math.random(); window.img=window....

    shaonbean 评论0 收藏0
  • 浅谈 Promise

    摘要:解决异步编程有两种主要方式事件模型和回调函数。将异步操作以同步操作的流程表达出来,避免了层层嵌套回调函数。方法是的别名,相当于函数的第一个参数传入,第二个参数传入发生错误时的回调函数。 JavaScript 解决异步编程有两种主要方式:事件模型和回调函数。但是随着业务越来越复杂,这两种方式已经不能满足开发者的需求了,Promise 可以解决这方面的问题。为了更好的理解 Promise ...

    李涛 评论0 收藏0
  • 简单学习 Promise 对象

    摘要:方法是的别名,用于指定发生错误时的回调函数。由于字符串不属于异步操作判断方法是字符串对象不具有方法,返回实例的状态从一生成就是,所以回调函数会立即执行。出错了等同于出错了出错了上面的代码生成一个对象的实例,状态为,回调函数会立即执行。 引言 Promise 是异步编程的一种解决方案,比传统的解决方案——回调和事件——更合理且强大。最近的项目要用到这个,就参照阮一峰老师的《ES6标准入门...

    muzhuyu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<