如何用 Promise.all 替换多个 async/await 调用?
Posted
技术标签:
【中文标题】如何用 Promise.all 替换多个 async/await 调用?【英文标题】:How to replace multiple async/await calls with Promise.all? 【发布时间】:2021-03-19 08:51:44 【问题描述】:我有以下 try/catch
块,它正在进行 3 个不同的 api 调用。
以下代码运行良好,但当firstData
具有大型数据集时,执行需要花费大量时间。
try
const firstData = await myservice1.myservice1Func();
for(let i=0; i<firstData.total; i++)
const hostName = firstData.rows[i]['hostname'];
if (hostName !== null && firstData.rows[i]['myservice1Id'] !== null)
const aRes = await myService2(hostName);
firstData.rows[i]['mylist'] =
aRes[0].dataValues;
if (hostName !== null && firstData.rows[i]['type'].includes('type1'))
const oRes = await myService3(hostName);
firstData.rows[i]['ores'] = oRes.rows[0];
if (hostName !== null && firstData.rows[i]['type'].includes('type2'))
const vRes = await myService4(hostName);
firstData.rows[i]['vRes'] = vRes.rows[0];
return firstData;
catch (err)
console.log(err);
这里,
const firstData =
"total": 2,
"rows": [
"hostname": "abc.com",
"ipAddress": "11.11.11.11",
"myservice1Id": "ee0f77c9-ef15",
"type": "type1"
,
"hostname": "cde.com",
"ipAddress": "12.12.12.12",
"type": "type2",
"myservice1Id": null
]
const aRes =
[
"listType": "list1",
"createdAt": "2020-12-07"
]
const oRes =
"rows": [
"status": "FAIL"
]
const vRes =
"rows": [
"status": "FAIL"
]
firstData
的最终返回值如下:
"total": 2,
"rows": [
"hostname": "abc.com",
"ipAddress": "11.11.11.11",
"myservice1Id": "ee0f77c9-ef15",
"type": "type1",
"oRes":
"status": "PASS"
,
"mylist":
"listType": "list1",
"createdAt": "2020-12-07"
,
"hostname": "cde.com",
"ipAddress": "12.12.12.12",
"type": "type2",
"myservice1Id": null,
"vRes":
"status": "FAIL"
]
在这里,需要注意的一点是所有 3 个if blocks
都可以并行执行,因为它们是相互独立的。
我可以使用Promise.all
来执行parallel
中的所有3 个if blocks
吗?
如果是,更新后的代码使用Promise.all
会是什么样子?
【问题讨论】:
【参考方案1】:最简单的调整是将每个 Promise 推送到 if
s 内的数组:
const proms = [];
if (hostName !== null && firstData.rows[i].myservice1Id !== null)
proms.push(
myService2(hostName)
.then(aRes => firstData.rows[i].mylist = aRes[0].dataValues)
);
// other ifs changed around the same way
await Promise.all(proms);
您还可以通过只检查一次hostName
来简化代码,看起来您正在迭代整个数组,这可以通过调用迭代器更轻松地完成:
try
const firstData = await myservice1.myservice1Func();
for (const row of firstData.rows)
const hostName = row.hostname;
if (hostName === null) continue;
const proms = [];
if (row.myservice1Id !== null)
proms.push(
myService2(hostName)
.then(aRes => row.mylist = aRes[0].dataValues)
);
// etc
【讨论】:
您能否建议在哪里包含for loop
?
当前代码中的相同位置。使用答案中的代码,您最多可以发出 3 个并行请求,这是非常合理的,我通常不想超出这个范围,尽管这取决于服务可以处理多少并行度。
最后,我应该做return proms;
吗?
不,您只需要答案中的await Promise.all(proms);
,然后在那之后,该行将被完全填充
我收到一个错误TypeError: Cannot read property 'dataValues' of undefined
你能告诉我在哪里添加未定义的检查吗?【参考方案2】:
您好,您有一些代码改动,
for(let i=0; i<firstData.total; i++)
const hostName = firstData.rows[i]['hostname'];
//check if condition inside the service and return a null (a promise)
Promise.all([myService2(hostName), myService3(hostName), myService4(hostName)]).then((values) =>
console.log(values);
//[resutl1,null,result3]
);
现在的问题是你必须等到最慢的迭代完成, 你可以通过使用承诺池来解决这个问题, @supercharge/promise-pool
MDN PromiseMedium Blog Source
【讨论】:
以上是关于如何用 Promise.all 替换多个 async/await 调用?的主要内容,如果未能解决你的问题,请参考以下文章