如何在 javascript 中同步异步地图函数
How to synchronize an async map function in javascript
我有一个异步映射函数,但希望它同步执行,因为我需要在同一个循环中使用第一个语句的输出。但是即使使用 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
modelVarients.map(async () => >...)
将所有的元素都转化为Promises,也就是全部开始执行。然后 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.
看起来你应该链你的承诺,而不是运行然后与Promise.all
并行
我有一个异步映射函数,但希望它同步执行,因为我需要在同一个循环中使用第一个语句的输出。但是即使使用 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
modelVarients.map(async () => >...)
将所有的元素都转化为Promises,也就是全部开始执行。然后 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.
看起来你应该链你的承诺,而不是运行然后与Promise.all