簡體   English   中英

更新 async forEach 以根據來自另一個集合的屬性更新每個文檔屬性

[英]Updating async forEach to update every document property based off property from another collection

我有這段代碼有效。 但是,我不確定為什么,我覺得它的行為可能不一致。

  await Listing.find({}, (err, listings) => {
    if (err) {
      console.log(err);
    }
    listings.forEach(async (listing) => {
      //console.log(listing);
      let championsUpdate = {};
      for (let key in listing["champions"]) {
        championsUpdate[key] = rankingDB[key];
      }

      await Listing.updateOne(
        { _id: listing._id },
        { $set: { champions: championsUpdate } }
      );
    });
  });

我幾乎找到了所有需要更新的列表,然后對於每個列表,我根據我之前檢索到的數據更新其中一個屬性。

到目前為止,它的行為一直正常,但我記得有人告訴我要避免在 forEach 循環中使用 async await,因為它的行為不像我們預期的那樣。 但我不知道為什么這是有效的,我是否應該避免使用 forEach 並使用 forOf。 我也擔心嵌套的異步等待。

有誰知道這樣的事情是否可以? 有關我的應用程序的更多上下文

因為 forEach 循環中的回調是異步的,所以調用 forEach 之后的事情可能會在 forEach 完成之前執行,並且它不會等待每次迭代完成后再繼續。
例如,在updateOne調用之前的 await 實際上是沒有意義的,因為外部異步 function 沒有被等待,這表明它可能沒有按照您的意願行事。

建議您不要在forEach中使用async的原因是它幾乎永遠不會按照您想要的方式運行,或者您實際上並不需要它,或者您可能會忘記您后來以這種方式調用它並且無意中導致稍后出現競爭條件(即:它使執行順序難以推理並且幾乎不可預測)。 如果您實際上不關心調用的結果、調用的時間和解析的時間,那么它是有效的。

下面是一個演示,展示了它如何導致意外結果。 隨機sleep以使每個.updateOne調用在隨機時間解決。 請注意,對console.log(`Will execute before...`)的調用在 forEach 迭代之前執行。

 async function runit() { await Listing.find({}, (err, listings) => { if (err) { console.log(err); } listings.forEach(async (listing) => { //console.log(listing); let championsUpdate = {}; for (let key in listing["champions"]) { championsUpdate[key] = rankingDB[key]; } await Listing.updateOne( { _id: listing._id }, { $set: { champions: championsUpdate } } ); }); }); console.log(`Will execute before the updateOne calls in forEach resolve`) } runit()
 <script> // mock data with sequential _id from 0...9 listings = Array(10).fill().map((_,_id)=>({_id, champions: {1:1,2:2}})) rankingDB = Array(10).fill({1:1.1,2:2.2}) // Promise that resolves in ms milliseconds function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // mock Listing Listing = { find(x, fn) { console.log('find') return new Promise(res=> res(fn(undefined,listings))) }, // updateOne resolves after random time < 1000 ms async updateOne({_id}) { await sleep(Math.random()*1000) console.log('updateOne with listing _id=',_id) } } </script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM