簡體   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