繁体   English   中英

JS:Async / await似乎不等待循环中的结果

[英]JS: Async/await doesn't seem to wait for result in a loop

我有一个异步映射功能。 如果没有文档,我将在其中创建一组文档。 应该将第一个创建的文档的ID设置为下一个文档的parent文档。

await Promise.all(data.map(async (o, index) => {
  const key = o.name
  const value = o.value
  const query = { [key]: value }
  const parentID = refID

  console.log(parentID);

  if (parentID) query.parent = parentID

  // Check if document is existing
  let ref = await References.findOne(query)
  refID = ref ? ref._id : undefined

  // If not existing, create it
  if (!refID) {
    const refInserted = await References.insertOne(query)
    refID = refInserted ? refInserted.insertedId : undefined
  }

  console.log(refID)
}))

因此,我希望此日志输出具有交替的refID和parentID:

undefined (parentID first run)
yBZWYJcWBoSzx9qwy (refID first run)
yBZWYJcWBoSzx9qwy (parentID second run)
23poGAbg85LCqkcZc (refID second run)
23poGAbg85LCqkcZc (parentID third run)
yBJYzedxftLe2Xm4r (refID third run)
yBJYzedxftLe2Xm4r (parentID fourth run)
PpzjuZ4vfrktNH4ez (refID fourth run)

但是我得到了

undefined
undefined
undefined
undefined
undefined
undefined
yBZWYJcWBoSzx9qwy
23poGAbg85LCqkcZc
yBJYzedxftLe2Xm4r
PpzjuZ4vfrktNH4ez

这表明它不是交替输出日志,而是运行在两个块中,尽管我已经为insertOne设置了await (使用mongo本机驱动程序)。 所以很明显我误会了一些东西:

我想我正在做的是,在这种情况下,该map类似于forEach循环:第一次运行后,将提取现有文档的ID或新创建的文档的ID(如果没有退出)。 在第二次运行中,此ID设置为parentID,因此对于第二个创建的文档,设置了父键。

这里的问题是,如果您希望同步进行评估,则不想使用Promise.all 这是因为Promise.all将接受一系列的诺言,然后允许这些诺言在任何时候都得到解决。 而是将操作包装在异步函数中,然后使用常规循环:

async function processData(data){
    for (var index = data.length - 1; i >= 0; i--) {
        const o = data[index];
        const key = o.name
        const value = o.value
        const query = { [key]: value }
        const parentID = refID

        console.log(parentID);

        if (parentID) query.parent = parentID

        // Check if document is existing
        let ref = await References.findOne(query)
        refID = ref ? ref._id : undefined

        // If not existing, create it
        if (!refID) {
          const refInserted = await References.insertOne(query)
          refID = refInserted ? refInserted.insertedId : undefined
        }

        console.log(refID)
    }
}

我从您的摘要中猜测,事情实际上正在按预期进行。 之所以会看到日志输出,是因为它将在继续之前为数组的每个项目运行映射函数的第一个“阶段”(阶段是直到下一个await调用的代码)。

请参阅以下代码段:

 var arr = [1,2,3,4,5] function timer(dur) { return new Promise(res => { setTimeout(res, dur); }); } async function doStuff() { console.log("Beginning block...") await Promise.all(arr.map(async (x) => { console.log("Starting phase 1 for item:", x); await timer(500); console.log("Phase 1 complete, starting phase 2 for item:", x); await timer(500); console.log("Phase 2 complete for item:", x); })); console.log("Block ended...") } doStuff() 

因此,尽管您会注意到每个项目的阶段都是依次运行的,但对于整个集合而言却并非如此。 例如,阶段1将针对每个阶段开始,然后针对每个阶段完成。 这仅仅是map是同步的,而传递的函数却不是同步的结果。

如果您绝对要强制一项完成所有阶段,然后再继续进行,则必须分别等待每个阶段,而不要使用Promise.all

 var arr = [1,2,3,4,5] function timer(dur) { return new Promise(res => { setTimeout(res, dur); }); } async function doStuff() { console.log("Beginning block...") for (const x of arr) { console.log("Starting phase 1 for item:", x); await timer(500); console.log("Phase 1 complete, starting phase 2 for item:", x); await timer(500); console.log("Phase 2 complete for item:", x); }; console.log("Block ended...") } doStuff() 

但是您会注意到完成此操作的时间明显更长,因为每个项目都无法再并行运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM