[英]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.