javascript - 当任何承诺都实现时,是否有可能脱离 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 设置(我不确定我是否都正确),请参考我的问题和答案。
解决方案
在这种情况下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
地方。
我认为你可以在生产代码中安全地使用它,只要你为将来阅读的任何人都很好地注释了这个代码块。
推荐阅读
- c# - 通过 Automapper 进行深度克隆,忽略层次结构中的特定属性
- hyperledger-fabric - 使用 Hyperledger Composer 文档在本地部署 Fabric 并出现错误
- python - 有什么方法可以进行虚拟缩进吗?
- typescript - Generics for Typesafe-Actions library
- javascript - 通过到 php
- c - C 中冒泡排序算法的运行时
- excel - 从工作表中读取父/子关系
- java - 如何在 dropwizard 项目中启动时运行 Liquibase 迁移?
- c# - Semaphoreslim 是否应该在控制器中而不是在链中的更下方?
- c# - 如何获取进程列表并将它们存储在 ListBox 中,每次进程列表更改时更改 ListBox