Promise.race数组中当有一个promise返回时,其它的promise就不再被then处理了?

看这个网页:https://www.kancloud.cn/kancl...
说是Promise.race 在第一个promise对象变为Fulfilled之后,并不会取消其他promise对象的执行。

但是在下面的代码中,需要在web上显示所有的platform当前状态是在线还是离线,对platformList中的每个platform构建一个promise,在promise里面进行一次ajax api调用,实际调试环境中,数组有两个元素,一个会api成功(resolve ok),另一个会失败(resolve not ok),,运行时发现then只运行了一次,只打印了一次Promise.race race get result就没有反应了,第二次ajax打印了“resolve not ok”之后,没有再调用then中的回调函数:

        var i
        var promiseArray = []
        const self = this
        for (i in self.platformList) {
          var p = new Promise(function(resolve, reject) {
            apiGetPlatformIsOnline(self.platformList[i].id)
              .then(response => {
                console.log("resolve ok")
                resolve(response.data)
              })
              .catch((err) => {
                console.log("resolve not ok")
                resolve(response.data)
              })
          });
          promiseArray.push(p)
        }

        Promise.race(promiseArray).then(function(results) {
          console.log("Promise.race race get result:", results)
        }).catch(function(results) {
          console.log("catch error,results", results);
        });

据说用ajax同步或ajax递归能解决问题,就想问问,这种场合到底还能不能用promise了?一些指标监控类的页面经常遇到这种情况,初始化时并发地撒出一大把异步的api查询请求,然后回复一个就处理一个,成功了显示查询结果,失败了就显示一个问号

阅读 8.9k
3 个回答

clipboard.png

Promise.race在第一个promise对象变为Fulfilled之后,并不会取消其他promise对象的执行。只是只有先完成的Promise才会被Promise.race后面的then处理。其它的Promise还是在执行的,只不过是不会进入promise.race后面的then内。

Promise.allPromise.race都是有使用场景的。
有些时候我们做一个操作可能得同时需要不同的接口返回的数据,这时我们就可以使用Promise.all
有时我们比如说有好几个服务器的好几个接口都提供同样的服务,我们不知道哪个接口更快,就可以使用Promise.race,哪个接口的数据先回来我们就用哪个接口的数据。

看你这个需求,这几个请求完全没有关系,所以就创建n个promise,然后在各自的回调里面做各自的事情不行吗?

Update2:
感觉好像没有必要用promise。

Update3:
在for循环里面使用let来声明i,就可以在then和catch里面使用i来分辨是哪个请求了。

// var i
// var promiseArray = []
const self = this
for (let i in self.platformList) {
    // var p = new Promise(function(resolve, reject) { // 这个位置的promise感觉也没有必要了
    apiGetPlatformIsOnline(self.platformList[i].id)
        .then(response => {
            console.log("resolve ok") // 在这里处理每个请求成功的操作
            // resolve(response.data)
        })
        .catch((err) => {
            console.log("resolve not ok") // 在这里处理每个请求失败的操作
            // resolve(response.data)
        })
    // });
    // promiseArray.push(p)
}

// 下面的这部分感觉没有必要
// Promise.race(promiseArray).then(function(results) {
//     console.log("Promise.race race get result:", results)
// }).catch(function(results) {
//    console.log("catch error,results", results);
// });

var successList = [];
var errorList = [];
request.map(getRequset).reduce((sequence, requestPromise) => sequence.then(() => requestPromise).then(message => { successList.push(message)}).catch(err => {errorList.push(err)})), Promise.resolve());
这个可以同时并发发送请求,但是处理还是需要一个一个来

race的意思是竞争,只要有一个promise返回整个race就会返回。

如果想限制需要有promise被resolve再返回,可以检查race的返回的promise数组,剔除掉被reject的promise,然后继续race。

实现起来并不复杂,难想的是如何得知哪个promise被reject了,js本身没有检查promise状态的API,所以你必须把所有promise挨个catch一把。

import { $log } from 'ts-log-debug';

function properRace<T>(promises: Array<Promise<T>>): Promise<T> {
  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 => {
    $log.debug('Promise rejected in `properRace`: ' + e);
    throw 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');
  });
}

export { properRace };
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏