首页 > 解决方案 > 当任何承诺都实现时,是否有可能脱离 await Promise.all (Chrome 80)

问题描述

我需要向多台服务器发送请求,以查看哪个服务器将响应我的请求,如果其中任何一个响应,我将进一步与该服务器交互。最简单的方法是按顺序发送我的请求,像这样

async function probing(servers) {
    for (const server of servers) {
        const result = await fetch(server)
        if (result.status == 200) {
            return result
        }
    }
}

但我希望加快探测过程,所以我将代码更改为

async function probing(servers) {
    results = await Promise.all(
        servers.map(async server => {
            return await fetch(server)
        })
    )
    for (const result of results) {
        if (result.status == 200) return result
    }
}

但我仍然需要等待所有的承诺完成。我真正需要的是,如果他们中的一个人已经解决了,然后我会从我的 probing() 中返回

那可能吗?

- - 更新 - -

感谢您的评论promise.any是解决方案(单线箭头功能可以进一步简化如下)

result = await Promise.any(
    servers.map(server => fetch(server))
)

---- 更新 2 ----

我曾认为Promise.any是要走的路,也是故事的结局。但不幸的是,事实并非如此!Promise.any仅适用于 Chrome 85+ 和 FF 79+,不像 Promise.all 适用于除 IE 之外的任何现代浏览器,请查看https://v8.dev/features/promise-combinators

我的客户需要我从 2020 年开始支持 Chrome 版本,即 Chrome 80+,我尝试用 Babel填充 Promise.any但失败了。

我们使用babel6,但我无法用 babel6 填充 Promise.any。我尝试升级到babel7 (有npx babel-upgrade --write一些曲折),现在使用 Promise.any() 的捆绑代码甚至不能用于 chrome 88。我问了另一个问题如何使用 babel 7 polyfill Promise.any() ?

所以现在我只需要恢复到 Promise.all。

---- 更新 3 ----

我终于Promise.any()用 Babel 7 制作了 polyfill,关键是使用core-js@3正确的 babelrc 设置(我不确定我是否都正确),请参考我的问题和答案。

标签: javascriptgoogle-chromeasync-awaitpromisepolyfills

解决方案


在这种情况下Promise.race()看起来很合理,但问题Promise.race()是在比赛中任何拒绝承诺都会使整个比赛崩溃。如果我们想要忽略个别拒绝并继续比赛,那么我们仍然有一个选择,在这种情况下,只有当所有承诺都被拒绝时,我们才必须执行一个操作来处​​理错误。

因此,如果我们发明Promise.invert()并与 Promise.all() 一起使用它,那么我们就会得到我们想要的。

var invert = pr => pr.then(v => Promise.reject(v), x => Promise.resolve(x));

让我们看看如何使用它;

var invert     = pr  => pr.then(v => Promise.reject(v), x => Promise.resolve(x)),
    random     = r   => ~~(Math.random()*r),
    rndPromise = msg => random(10) < 3 ? Promise.reject("Problem..!!!")
                                       : new Promise((v,x) => setTimeout(v,random(1000),msg)),
    promises   = Array.from({length: 4}, (_,i) => rndPromise(`Promise # ${i}.. The winner.`));

Promise.all(promises.map(pr => invert(pr)))
       .then(e => console.log(`Error ${e} happened..!!`))
       .catch(v => console.log(`First successfully resolving promise is: ${v}`));

因此,由于 promise 被反转,现在catch是我们处理结果的地方,而是处理错误的then地方。

我认为你可以在生产代码中安全地使用它,只要你为将来阅读的任何人都很好地注释了这个代码块。


推荐阅读