首頁 > web前端 > js教程 > forEach 與 for:非同步對決!

forEach 與 for:非同步對決!

DDD
發布: 2025-01-07 22:41:41
原創
612 人瀏覽過

forEach vs. for: The Asynchronous Showdown!

了解循環選擇如何影響非同步效能

在我最近的專案中,我需要更新 NoSQL 資料庫中的大量記錄—超過一千筆。由於一次性更新它們是不可行的,而且該過程也是非同步的,因此我決定以較小的批次(每批 20 條記錄)處理它們。我使用 forEach 在循環中實現了這一點,其中每組 20 個將在進入下一組之前更新。然而,在將這種方法付諸實踐後,我注意到並非所有記錄都按預期更新,即使在這些較小的批次中也是如此。例如,當我嘗試更新一批 25 筆記錄時,只有 10 筆記錄成功更新。其他10筆記錄沒有日誌,更新失敗的記錄數量隨機變化-有時12條,有時5條,有時7條。

經過進一步調試,我發現這些記錄很可能在更新過程中被跳過。現在,為什麼會發生這種情況?讓我們探討這個問題,以了解該行為並確定背後的潛在原因。

問題
經過一些研究,我發現在 forEach 循環中使用非同步函數而沒有適當的機制來等待所有迭代可能會導致問題。在這種情況下,我們在 forEach 循環中使用了 async/await,但沒有確保等待所有迭代(請參閱下面的程式碼):

async function patchRecords(records) {
    // Here, the length of records is 25
    let successfulUpdates = 0; // Initialize a counter for successful updates

    records.forEach(async (item) => {
        await databaseName.patch(item);
        successfulUpdates++; // Increment counter on successful update
    });
    // Return the number of records updated successfully
    return successfulUpdates;
}

const response = await patchRecords(records); // Make sure to await this call
登入後複製
登入後複製

在上面的程式碼中,沒有任何機制可以確保循環的所有非同步迭代都完成。 forEach 方法會觸發多個非同步呼叫來修補記錄,但 patchRecords 函數很快到達回傳語句,而無需等待這些修補完成。因此,當更新在背景處理時,功能會繼續執行,而無需等待更新完成。這可能會導致一些待處理的承諾仍未兌現,從而可能導致跳過或丟棄更新。


那我們該如何解決這個問題呢?在我們開始討論解決方案之前,我們首先了解迭代資料的不同方法。從根本上來說,有兩種方法:順序迭代資料或並行

如果您想以順序方式非同步迭代數據,使用 forEach 循環可能會導致我們討論的問題。相反,最好使用現代的for…of 循環或簡單的for 循環,因為它們允許await 正常工作並確保所有更新都不會處理被跳過(請參閱下面的程式碼)。

async function patchRecords(records) {
    // Here, the length of records is 25
    let successfulUpdates = 0; // Initialize a counter for successful updates

    records.forEach(async (item) => {
        await databaseName.patch(item);
        successfulUpdates++; // Increment counter on successful update
    });
    // Return the number of records updated successfully
    return successfulUpdates;
}

const response = await patchRecords(records); // Make sure to await this call
登入後複製
登入後複製

另一方面,如果你想並行處理記錄,再次使用 forEach 將無法運作。雖然每個非同步回調確實會傳回一個承諾,但其中一些承諾可能仍然未實現,因為它們沒有被等待。相反,使用 map 產生 Promise 數組,然後使用 Promise.all 等待它們(請參閱下面的程式碼)。

async function patchRecords(records) {
    let successfulUpdates = 0; // Counter for successful updates

    for (const item of records) {
        try {
            // Query to patch each record
            await databaseName.patch(item);
            successfulUpdates++; // Increment counter on success
        } catch {
            // Handle any errors
        }
    }

    return successfulUpdates; // Return the number of records updated successfully
}

const response = await patchRecords(records); // Make sure to await this call
登入後複製

這顯示了選擇正確的循環方法如何極大地影響非同步操作的預期結果。您使用的循環類型 - 無論是 forEach、for...of 或標準 for 循環 - 對於程式碼管理非同步任務的效果起著至關重要的作用。

總結

  • 挑戰:使用forEach批次更新記錄導致更新不一致,許多記錄被跳過。
  • 根本原因: forEach 不等待非同步操作完成,導致未實現的承諾。
  • 解決方案: 使用 for…of 循環順序等待每個記錄更新以確保準確性,或使用 Map 和 Promise.all 進行並發更新。

我解釋清楚了嗎?請在下面的評論中告訴我。

我很高興分享我的經驗,希望你也覺得它很有價值!由於我仍在探索這個領域,我希望得到您的回饋和建議。 ☺️ 如果您發現我可以改進的地方,或者有您希望我涵蓋的主題,請隨時與我們聯繫! ?網站。我很高興能在您的幫助下學習和成長。 ??

以上是forEach 與 for:非同步對決!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板