javascript - NodeJS - 在 Array.map 中使用 Async/Await 和“if”语句
问题描述
我有一个循环遍历对象的递归函数。它查找具有名称的键subcomponent
(始终是一个数组)并在每个subcomponent
子节点上执行一个异步函数,其输出用于替换子节点的数据。
在下面的示例中populateSubcomponent()
是异步函数。
代码:
async function doPopulate(data) {
Object.keys(data).map((key) => {
if (typeof data[key] === 'object') { // We want to do a recursive check on the data so are interested in any objects (arrays) at this point
if (key === 'subcomponent') { // If we have an object (array) with key `subcomponent` we want to populate each of its children
const promises = data[key].map(subcomponent => populateSubcomponent(subcomponent));
return Promise.all(promises).then((output) => {
data[key] = output;
console.log('1');
});
}
doPopulate(data[key]); // Check recursively
console.log('2');
}
console.log('3');
return data;
});
}
doPopulate(data);
我的期望是每个console.log
数字都应该按顺序触发,但我却得到2
, 3
, then 1
。结果,递归函数在异步函数完成之前运行,因此永远不会按预期替换子函数;我得到了正确的结果,1
但它没有传递给2
or 3
。
如何最好地将递归doPopulate()
调用与if
语句结合起来?
我查看了以下 SO 帖子:
但我无法将任何答案与我自己的问题联系起来,主要是因为我if
在递归函数中有一个语句,我不确定如何在异步内容的上下文中处理它。
编辑
感谢大家的评论,我想出了以下内容:
async function doPopulate(data) {
const promisesOuter = Object.keys(data).map(async (key) => {
if (typeof data[key] === 'object') { // We want to do a recursive check on the data so are interested in any objects (arrays) at this point
if (key === 'subcomponent') { // If we have an object (array) with key `subcomponent` we want to populate each of its children
const promisesInner = data[key].map(subcomponent => populateSubcomponent(subcomponent));
data[key] = await Promise.all(promisesInner);
}
await doPopulate(data[key]); // Check recursively
}
return data;
});
return Promise.all(promisesOuter);
}
return doPopulate(data);
由于这一切都发生在 NodeJS 流中(使用through2),我还需要使流函数异步:
const through = require('through2');
return through.obj(async (file, enc, done) => {
const data = JSON.parse(file.contents.toString());
await doPopulate(data);
file.contents = Buffer.from(JSON.stringify(data));
return done(null, file);
});
解决方案
只要下一个 Promise 依赖于前一个 Promise,您就必须依次等待每个 Promise。如果它们可以同时完成,您只需聚合 Promise 并将它们与Promise.all
. 顺便说一句,async
如果您需要使用await
. 否则没有理由做这个函数async
。
如果您想按顺序等待每个承诺,您可以像这样重写它:
function doPopulate(data) {
return Object.keys(data).map(async (key) => {
if (typeof data[key] === 'object') { // We want to do a recursive check on the data so are interested in any objects (arrays) at this point
if (key === 'subcomponent') { // If we have an object (array) with key `subcomponent` we want to populate each of its children
const promises = data[key].map((subcomponent) =>
populateSubcomponent(subcomponent)
);
data[key] = await Promise.all(promises);
console.log('1');
}
await doPopulate(data[key]); // Check recursively
console.log('2');
}
console.log('3');
return data;
});
}
推荐阅读
- brainfuck - Brainfuck中的间接寻址
- java - 如何更改weblogic的springboot上下文路径?
- arrays - Firestore 数组中的排序顺序
- regex - 正则表达式检查特定电话号码或分机
- verilog - Verilog 中的 Inter & Intra Delay 与 Blocking & NBA 的混淆
- angular-material - 数据表不显示我的数据源数组
- c - C 程序预先添加,什么时候应该添加
- azure - 如何通过我拥有的 Graph API 从 Azure 获取所有组?
- python - Python使用哪种算法作为索引方法?
- javascript - 使用 for 循环增量打印数组项