NodeJS - 在 Array.map 中使用 Async/Await 和“if”语句
Posted
技术标签:
【中文标题】NodeJS - 在 Array.map 中使用 Async/Await 和“if”语句【英文标题】:NodeJS - Using Async/Await inside Array.map with 'if' statement 【发布时间】:2019-01-03 19:53:39 【问题描述】:我有一个循环遍历对象的递归函数。它查找名称为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 帖子:
Using async/await inside for loop Best way to call an async function within map? Async/Await inside Array#map() Use async await with Array.map但我无法将任何答案与我自己的问题联系起来,主要是因为我的递归函数中有一个 if
语句,我不确定如何在上下文中处理它异步的东西。
编辑
感谢大家的cmets,我想出了以下内容:
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);
);
【问题讨论】:
使用await doPopulate(data[key])
。为此,您还必须回调.map
async
。事实上你不需要doPopulate
async
;你只需要回报承诺。
@ExplosionPills Object.keys(data).map(async (key) =>
(第2行)和await doPopulate(data[key])
(第14行)似乎没有做任何事情......我不是已经用return Promise.all(promises).then((output) =>
返回了承诺吗?跨度>
不,因为在您当前的迭代中 doPopulate(data[key])
在 data[key] = output;
之前运行
@KevinB - 是的......这基本上是我的问题 - 我不确定如何正确构建我的代码,以便 doPopulate(data[key])
等待 if
语句完成......跨度>
@GarethJames 为什么不能在 promise 的 .then AND 语句中?
【参考方案1】:
只要下一个 Promise 依赖于前一个 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;
);
【讨论】:
为此干杯!不太好用,但使用data[key] = await Promise.all(promises)
找出答案...【参考方案2】:
事实证明,我需要按照 @Bergi 在 cmets 中的建议返回两组承诺:
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);
);
【讨论】:
以上是关于NodeJS - 在 Array.map 中使用 Async/Await 和“if”语句的主要内容,如果未能解决你的问题,请参考以下文章