如何在 javascript 中同步异步映射函数
Posted
技术标签:
【中文标题】如何在 javascript 中同步异步映射函数【英文标题】:How to synchronize an async map function in javascript 【发布时间】:2020-12-24 12:15:08 【问题描述】:我有一个异步映射函数,但希望它同步执行,因为我需要在同一个循环中使用第一条语句的输出。但是即使使用 await 语句,地图也会异步运行,请您帮助理解为什么会发生这种情况。
我的用例是如果不存在则将记录插入 mongodb 并在循环中存在时更新它。 数据存在于数据库中,但在循环内查找失败,但在外部工作。
我的代码:
const doSomethingAsync = () =>
return new Promise(resolve =>
setTimeout(() =>
resolve(Date.now());
, 1000);
);
;
await Promise.all(
modelVarients.map(async varient =>
console.log(`varient: $varient._id`);
console.log('1');
const onlineDevice = await Device.findOne(
model: varient._id,
);
console.log('2');
await doSomethingAsync();
console.log('3');
await doSomethingAsync();
console.log(JSON.stringify(onlineDevice));
await doSomethingAsync();
console.log('4');
return varient;
)
);
我得到的日志:
varient: 8 pro
1
varient: note
1
varient: iphone x
1
2
2
2
3
3
3
null
null
null
4
4
4
但我期望得到的:
varient: 8 pro
1
2
3
<actual response from db for 8 pro>
4
varient: note
1
2
3
<actual response from db for note>
4
varient: iphone x
1
2
3
<actual response from db for iphone x>
4
【问题讨论】:
这能回答你的问题吗? Is Node.js native Promise.all processing in parallel or sequentially? 使用 await modeVariants.reduce( async (...) => ) 而不是 map @olkvin 谢谢,我会尝试在我的代码中实现 @EdwardRomero 感谢您向我指出一个类似的问题,是的,它帮助我了解了 reduce 以及如何链接承诺,下面来自 sashee 使用 async/await 的答案也非常有帮助 【参考方案1】:看起来你应该链接你的承诺,而不是与Promise.all
并行运行
【讨论】:
【参考方案2】:modelVarients.map(async () => >...)
将所有元素转换为 Promise,这意味着它们都开始执行。然后Promise.all()
收集它们并等待所有这些,这就是为什么你可以使用这个结构来等待map
完成。这是并行处理。
您需要的是顺序处理,您可以使用reduce
来完成,如下所示:
await modelVarients.reduce(async (memo, varient) =>
await memo;
// all the other things
, Promise.resolve())
reduce
在某种意义上类似于map
,它为数组中的所有元素创建一个 Promise,但是有一个 当前值 从一个元素传递到另一个元素.在这种情况下,第一个是Promise.resolve()
,第二个是第一个的结果,依此类推。使用await memo
,您可以等待上一个结果。
使用reduce
,最后一个元素将等待前一个元素,它等待前一个元素,以此类推,因此不需要Promise.all。
我写过关于 map 和 reduce 如何使用异步函数的文章,它们将帮助您了解全局。
【讨论】:
使用reduce
和async function
作为回调是一个坏主意,它效率低下而且很容易完全出错。
@Bergi 你能详细说明为什么你认为这是一个坏主意,当我研究 reduce 时,甚至官方文档也有一个类似的例子 developer.mozilla.org/en-US/docs/Web/javascript/Reference/…
@Sai 使用的是then
而不是await
,并且在数组中链接(少数)不同的函数,而不是在数组中的(许多)项上链接相同的函数。
一般来说,只需使用for … of
循环和await
- 更简单、更短、更快。
es-lint 不鼓励 for ... of when 此错误:“迭代器/生成器需要 regenerator-runtime,这对于本指南来说太重了,无法允许它们。另外,应避免循环以支持数组迭代。” eslint.org/docs/rules/no-restricted-syntax 有什么想法吗?以上是关于如何在 javascript 中同步异步映射函数的主要内容,如果未能解决你的问题,请参考以下文章