我最近的任务是构建一个微服务,该服务需要发出数千个HTTP请求并处理响应。为了创建这种情况的简单模拟,我将使用一个 fake 函数,该函数接受任意值并返回解析为包含值和间隔的对象:requestPromise
const {promisify} = require('util')
const sleep = promisify(setTimeout)const request = async(data) => {
let time = Math.random() * 1000
await sleep(time)
return {data, time}
}
我有一堆包含请求参数数据的记录,所以我做的第一件事就是查询这些记录。对于此示例,我们将使用整数数组来模拟记录。我的第一直觉(我经验不足)是遍历记录数组,发出每个HTTP请求并将结果推送到新数组:
async function main() {
const records = Array.from(new Array(10)).map((e, i) => i)
let responses = []
console.time('Inline')
for (let i = 0; i < records.length; i++) {
let response = await request(records[i])
responses.push(response)
}
console.log(JSON.stringify(responses, null, 2))
console.timeEnd('Inline')
}
这工作正常,但我们必须在发出下一个请求之前等待每个响应,这意味着这可能需要长达 10 秒才能执行。结果如下所示:
[
{
"data": 0,
"time": 48.95140139293264
},
{
"data": 1,
"time": 351.42969859007377
},
...
]
Inline: 5210.4460449ms
5秒是一段很长的时间。现在让我们看看如何同时执行这些请求。我们可以将每个调用推送到一个数组中,并使用 Promise.all() 等待它们全部解析:request
async function main() {
const records = Array.from(new Array(10)).map((e, i) => i)
console.time('Concurrent')
let promises = []
for (let i = 0; i < records.length; i++) {
promises.push(request(records[i]))
}
let responses = await Promise.all(promises)
console.log(JSON.stringify(responses, null, 2))
console.timeEnd('Concurrent')
}
瞧,我们刚刚加快了服务速度!结果如下所示:records.length
[
{
"data": 0,
"time": 160.08417354131944
},
{
"data": 1,
"time": 560.08495847237463
},
...,
{
"data": 9,
"time": 223.39482395749209
}
]
Concurrent: 560.08495847237463ms
使用这种非阻塞方法会在所有承诺全部完成后立即获取它们的结果,因此总执行时间仅比最慢的 HTTP 请求大几毫秒。此相同技术可用于任何异步操作集合。responses
只是为了好玩,让我们在一行中使用Array.map:
let responses = await Promise.all(records.map(record => request(record)))
我希望这有帮助,快乐编码。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/292561.html