成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

你在 forEach 里寫的 await,其實根本沒在等!

開發
forEach和 async/await的這個組合,就像一對貌合神離的“情侶”,看起來般配,實則互相“背叛”。這個坑,我結結實實地踩過,而且不止一次。

forEach和 async/await的這個組合,就像一對貌合神離的“情侶”,看起來般配,實則互相“背叛”。這個坑,我結結實實地踩過,而且不止一次。

故事的開始:一個看似無害的需求

想象一下,接到一個需求:批量更新一組用戶的狀態。后端提供了一個接口 updateUser(userId),它是一個返回 Promise 的異步函數。第一反應可能就是這樣寫:

const userIds = [1, 2, 3, 4, 5];

async function updateUserStatus(id) {
 console.log(`開始更新用戶 ${id}...`);
 // 模擬一個需要 1 秒的網絡請求
 await new Promise(resolve => setTimeout(resolve, 1000)); 
 console.log(`? 用戶 ${id} 更新成功!`);
 return { success: true };
}

async function batchUpdateUsers(ids) {
 console.log("--- 開始批量更新 ---");

  ids.forEach(async (id) => {
    await updateUserStatus(id);
  });

 console.log("--- 所有用戶更新完畢!---"); // ?? 問題的根源在這里!
}

batchUpdateUsers(userIds);

運行這段代碼,控制臺輸出了什么?不是期望的按順序等待,而是這樣的結果:

看到了嗎?“所有用戶更新完畢!”這句話幾乎是立即打印出來的,它根本沒有“等待”任何 updateUserStatus函數的完成。

問題剖析:forEach到底干了什么?

forEach被設計為同步迭代器。它的工作很簡單:遍歷數組中的每個元素,并為每個元素同步地調用你提供的回調函數。它不關心你的回調函數是同步的還是異步的,也不關心它返回什么。

換句話說,forEach的內心獨白是:

“我的任務就是觸發,觸發,再觸發。至于你傳進來的那個 async函數什么時候執行完?抱歉,那不歸我管,我不會等它的。”

正確的姿勢:如何真正地“等待”?

既然 forEach不行,那我們該用什么?答案是使用那些“懂” Promise 的循環方式。

方案一:老實人 for...of循環(順序執行)

如果我們需要按順序、一個接一個地執行異步操作,for...of循環是你的最佳選擇。它是 async/await的天作之合。

async function batchUpdateUsersInOrder(ids) {
  console.log("--- 開始批量更新 (順序執行) ---");

  for (const id of ids) {
    // 這里的 await 會實實在在地暫停 for 循環的下一次迭代
    await updateUserStatus(id); 
  }

  console.log("--- 所有用戶更新完畢!(這次是真的) ---");
}

運行結果:

這完全符合我們的直覺:等待上一個完成后,再開始下一個。

方案二:效率先鋒 Promise.all+ map(并行執行)

在很多場景下,我們并不需要嚴格地按順序執行。這些異步任務之間沒有依賴關系,完全可以并行處理以提高效率。這時,map和 Promise.all的組合就閃亮登場了。

  • Array.prototype.map:與 forEach不同,map會返回一個新數組。當我們給它一個 async函數時,它會同步地返回一個由 pendingPromise 組成的數組。
  • Promise.all:這個方法接收一個 Promise 數組,并返回一個新的 Promise。只有當數組中所有的 Promise 都成功完成(resolved)時,這個新的 Promise 才會完成。
async function batchUpdateUsersInParallel(ids) {
 console.log("--- 開始批量更新 (并行執行) ---");

 // 1. map 會立即返回一個 Promise 數組
 const promises = ids.map(id => updateUserStatus(id));

 // 2. Promise.all 會等待所有 promises 完成
 await Promise.all(promises);

 console.log("--- 所有用戶更新完畢!(這次是真的,而且很快) ---");
}

運行結果:

圖片圖片

這種方式的總耗時約等于最慢的那個異步任務的耗時,效率極高。

方案三:更靈活的 for...in和傳統 for循環

for...in(用于遍歷對象鍵)和傳統的 for (let i = 0; ...)循環同樣支持 await。它們的工作方式與 for...of類似,都會等待 await的 Promise 完成。

// 傳統 for 循環
for (let i = 0; i < ids.length; i++) {
  await updateUserStatus(ids[i]);
}

為了防止你和我一樣踩坑,這里有一份速記備忘錄:需要按順序執行使用 for...of;需要并行執行,提高效率使用 Promise.all+ map,性能最佳,但要注意并發數過高可能帶來的問題;絕對不要用 forEach,它不會等待我們的 await,它只會無情地觸發。

責任編輯:趙寧寧 來源: JavaScript
相關推薦

2015-09-22 10:59:45

iOS 9功能

2024-07-04 13:22:45

2018-04-03 10:54:41

阿里游戲云

2024-02-05 08:01:52

Javadll動態鏈接

2019-06-18 09:28:34

iOS 13手機黑暗模式

2022-12-01 17:17:09

React開發

2014-05-29 11:14:35

2014-04-21 09:56:50

2011-06-21 16:38:34

SEO

2022-06-28 10:58:48

協議通信加密

2010-08-26 11:00:23

2021-09-16 09:38:12

開發項目代碼

2024-03-12 08:37:32

asyncawaitJavaScript

2022-08-19 10:27:39

系統模型

2019-11-29 20:00:40

Linuxdate命令

2017-10-14 22:45:55

前端

2012-05-08 08:55:56

2019-03-04 09:22:52

阿里巴巴foreach Java

2023-04-26 08:43:28

GoCGO語言

2018-04-09 13:03:28

華為云游戲
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 香蕉视频91 | 欧美小视频在线观看 | 黄色片在线免费看 | 欧美午夜在线 | 欧美日韩中文国产一区发布 | 欧美日韩高清免费 | 久久国产精99精产国高潮 | 日韩av在线免费 | 日韩三级在线 | 亚洲午夜精品 | 国产一区精品在线 | 国产精品一区二区视频 | 黄网站在线观看 | 国产欧美日韩精品一区二区三区 | 天天躁日日躁狠狠很躁 | 精品国产精品国产偷麻豆 | 天天躁日日躁aaaa视频 | 精品欧美一区二区精品久久久 | 久热免费在线 | 国产一区二区三区在线观看免费 | 男人的天堂中文字幕 | 欧美日韩国产免费 | 亚洲成人av一区二区 | 能看的av | 亚洲va国产日韩欧美精品色婷婷 | 精品国产一二三区 | 亚洲欧美国产毛片在线 | 九九亚洲精品 | 精品国产乱码久久久久久丨区2区 | 亚洲高清一区二区三区 | 91免费福利视频 | 久久综合久| 在线精品国产 | 国产成人精品一区二区三区视频 | 自拍偷拍亚洲欧美 | 亚洲一二三区在线观看 | 精品一区av | 在线观看亚洲精品 | 综合久 | www.日本在线播放 | 黄网在线观看 |