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数字都应该按顺序激发,但我得到的是23,然后是1。因此,递归函数在异步函数完成之前运行,因此永远不会按预期替换子函数;我在1得到了正确的结果,但它没有传递给23

如何最好地将递归doPopulate()调用与if语句结合起来?

我看过以下SO帖子:

  • 在循环内部使用async/await
  • 在映射中调用异步函数的最佳方式
  • 数组#map((内的异步/等待
  • 将async await与Array.map一起使用

但我无法将任何答案与我自己的问题联系起来,主要是因为我的递归函数中有一个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.all一起等待它们。顺便说一下,如果您需要使用await,则只需要async关键字。否则就没有理由将函数设为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;
});
}

事实证明,正如@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);
});

最新更新