我有一个遍历对象的递归函数。它查找名称为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
和1
。结果,递归函数在异步函数完成之前运行,因此永远不要按预期替换子级。我在1
上得到了正确的结果,但是没有传递给2
或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);
});
答案 0 :(得分:0)
只要下一个诺言依赖于前一个诺言,您就必须顺序等待每个诺言。如果可以同时完成它们,则只需汇总承诺并与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;
});
}
答案 1 :(得分:0)
结果证明,我需要按照评论中@Bergi的建议归还两套承诺:
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),我还需要使流功能也异步:
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);
});