JavaScript循環如何使用 async/await?需要注意些什麼?
async
與 await
的使用方式相對簡單。但當你嘗試在循環中使用await
時,事情就會變得更複雜。
在本文中,分享一些在如果循環中使用await
值得注意的問題。
準備一個例子
對於這篇文章,假設你想從水果籃中獲得水果的數量。
const fruitBasket = { apple: 27, grape: 0, pear: 14 };
你想從fruitBasket
獲得每個水果的數量。要取得水果的數量,可以使用getNumFruit
函數。
const getNumFruit = fruit => { return fruitBasket[fruit]; }; const numApples = getNumFruit('apple'); console.log(numApples); //27
現在,假設fruitBasket
是從伺服器上獲取,這裡我們使用 setTimeout
來模擬。
const sleep = ms => { return new Promise(resolve => setTimeout(resolve, ms)) }; const getNumFruie = fruit => { return sleep(1000).then(v => fruitBasket[fruit]); }; getNumFruit("apple").then(num => console.log(num)); // 27
最後,假設你想使用await
和getNumFruit
來取得非同步函數中每個水果的數量。
const control = async _ => { console.log('Start') const numApples = await getNumFruit('apple'); console.log(numApples); const numGrapes = await getNumFruit('grape'); console.log(numGrapes); const numPears = await getNumFruit('pear'); console.log(numPears); console.log('End') }
在for 循環中使用await
首先定義一個存放水果的陣列:
const fruitsToGet = [“apple”, “grape”, “pear”];
循環遍歷這個陣列:
const forLoop = async _ => { console.log('Start'); for (let index = 0; index <p>在<code>for</code> #循環中,過上使用<code>getNumFruit</code>來取得每個水果的數量,並將數量列印到控制台。 </p><p>由於<code>getNumFruit</code>傳回一個<code>promise</code>,我們使用 <code>await</code> 來等待結果的回傳並列印它。 </p><pre class="brush:php;toolbar:false">const forLoop = async _ => { console.log('start'); for (let index = 0; index <p>當使用<code>await</code>時,希望JavaScript暫停執行,直到等待 promise 回傳處理結果。這意味著<code>for</code>循環中的<code>await</code> 應該按順序執行。 </p><p>結果就如你所預料的。 </p><pre class="brush:php;toolbar:false">“Start”; “Apple: 27”; “Grape: 0”; “Pear: 14”; “End”;
這種行為適用於大多數迴圈(例如while
和for-of
迴圈)…
但是它不能處理需要回呼的循環,例如forEach
、map
、filter
和reduce
。在接下來的幾節中,我們將研究await
如何影響forEach
、map和filter
。
在 forEach 迴圈中使用 await
首先,使用 forEach
對陣列進行遍歷。
const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End') }
接下來,我們將嘗試使用getNumFruit
來取得水果數量。 (注意回呼函數中的async
關鍵字。我們需要這個async
關鍵字,因為await
在回呼函數中)。
const forEachLoop = _ => { console.log('Start'); fruitsToGet.forEach(async fruit => { const numFruit = await getNumFruit(fruit); console.log(numFruit) }); console.log('End') }
我期望控制台列印以下內容:
“Start”; “27”; “0”; “14”; “End”;
但實際結果是不同的。在forEach
迴圈中等待回傳結果之前,JavaScrip先執行了 console.log('End')。
實際控制台列印如下:
‘Start’ ‘End’ ‘27’ ‘0’ ‘14’
JavaScript 中的forEach
不支援promise 感知,也支援async
和await
,所以不能在forEach
上使用await
。
在map 中使用await
如果在map
中使用await
, map
始終傳回promise
數組,這是因為非同步函數總是傳回promise
。
const mapLoop = async _ => { console.log('Start') const numFruits = await fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit; }) console.log(numFruits); console.log('End') } “Start”; “[Promise, Promise, Promise]”; “End”;
如果你在map
中使用await
,map
總是回傳promises
,你必須等待promises
陣列得到處理。或透過await Promise.all(arrayOfPromises)
來完成此操作。
const mapLoop = async _ => { console.log('Start'); const promises = fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit; }); const numFruits = await Promise.all(promises); console.log(numFruits); console.log('End') }
運行結果如下:
如果你願意,可以在promise
中處理回傳值,解析後的將是返回的值。
const mapLoop = _ => { // ... const promises = fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit + 100 }) // ... } “Start”; “[127, 100, 114]”; “End”;
在 filter 迴圈中使用 await
#當你使用filter
時,希望篩選具有特定結果的陣列。假設過濾數量大於20的陣列。
如果你正常使用filter
(沒有await),如下:
const filterLoop = _ => { console.log('Start') const moreThan20 = fruitsToGet.filter(async fruit => { const numFruit = await fruitBasket[fruit] return numFruit > 20 }) console.log(moreThan20) console.log('END') }
運行結果
Start ["apple"] END
filter
中的await
不會以相同的方式運作。事實上,它根本不起作用。
const filterLoop = async _ => { console.log('Start') const moreThan20 = await fruitsToGet.filter(async fruit => { const numFruit = fruitBasket[fruit] return numFruit > 20 }) console.log(moreThan20) console.log('END') } // 打印结果 Start ["apple", "grape", "pear"] END
為什麼會發生這種情況?
當在filter
回呼中使用await
時,回調總是一個promise
。由於promise
總是真的,數組中的所有項目都通過filter
。在filter
使用 await
類別以下這段程式碼
const filtered = array.filter(true);
在filter
使用 await
正确的三个步骤
- 使用
map
返回一个promise 数组 - 使用
await
等待处理结果 - 使用
filter
对返回的结果进行处理
const filterLoop = async _ => { console.log('Start'); const promises = await fruitsToGet.map(fruit => getNumFruit(fruit)); const numFruits = await Promise.all(promises); const moreThan20 = fruitsToGet.filter((fruit, index) => { const numFruit = numFruits[index]; return numFruit > 20; }) console.log(moreThan20); console.log('End') }
在 reduce 循环中使用 await
如果想要计算 fruitBastet
中的水果总数。 通常,你可以使用reduce
循环遍历数组并将数字相加。
const reduceLoop = _ => { console.log('Start'); const sum = fruitsToGet.reduce((sum, fruit) => { const numFruit = fruitBasket[fruit]; return sum + numFruit; }, 0) console.log(sum) console.log('End') }
运行结果:
当你在 reduce
中使用await
时,结果会变得非常混乱。
const reduceLoop = async _ => { console.log('Start'); const sum = await fruitsToGet.reduce(async (sum, fruit) => { const numFruit = await fruitBasket[fruit]; return sum + numFruit; }, 0) console.log(sum) console.log('End') }
[object Promise]14
是什么 鬼??
剖析这一点很有趣。
- 在第一次遍历中,
sum
为0
。numFruit
是27
(通过getNumFruit(apple)
的得到的值),0 + 27 = 27
。 - 在第二次遍历中,
sum
是一个promise
。 (为什么?因为异步函数总是返回promises
!)numFruit
是0
.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]
字符串。[object Promise] + 0
是object Promise] 0
。 - 在第三次遍历中,
sum
也是一个promise
。numFruit
是14
.[object Promise] + 14
是[object Promise] 14
。
解开谜团!
这意味着,你可以在reduce
回调中使用await
,但是你必须记住先等待累加器!
const reduceLoop = async _ => { console.log('Start'); const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => { const sum = await promisedSum; const numFruit = await fruitBasket[fruit]; return sum + numFruit; }, 0) console.log(sum) console.log('End') }
但是从上图中看到的那样,await
操作都需要很长时间。 发生这种情况是因为reduceLoop
需要等待每次遍历完成promisedSum
。
有一种方法可以加速reduce
循环,如果你在等待promisedSum之前先等待getNumFruits()
,那么reduceLoop
只需要一秒钟即可完成:
const reduceLoop = async _ => { console.log('Start'); const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => { const numFruit = await fruitBasket[fruit]; const sum = await promisedSum; return sum + numFruit; }, 0) console.log(sum) console.log('End') }
这是因为reduce
可以在等待循环的下一个迭代之前触发所有三个getNumFruit
promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。
在reduce中使用wait最简单(也是最有效)的方法是
- 使用
map
返回一个promise 数组 - 使用
await
等待处理结果 - 使用
reduce
对返回的结果进行处理const reduceLoop = async _ => {
console.log('Start');const promises = fruitsToGet.map(getNumFruit);
const numFruits = await Promise.all(promises);
const sum = numFruits.reduce((sum, fruit) => sum + fruit);console.log(sum)
console.log('End')
}
这个版本易于阅读和理解,需要一秒钟来计算水果总数。
从上面看出来什么
- 如果你想连续执行
await
调用,请使用for
循环(或任何没有回调的循环)。 - 永远不要和
forEach
一起使用await
,而是使用for
循环(或任何没有回调的循环)。 - 不要在
filter
和reduce
中使用await
,如果需要,先用map
进一步骤处理,然后在使用filter
和reduce
进行处理。
原文地址:https://medium.com/free-code-camp/javascript-async-and-await-in-loops-30ecc5fb3939
更多编程相关知识,请访问:编程学习网站!!
以上是JavaScript循環如何使用 async/await?需要注意些什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務
