小編給大家分享一下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') }
首先定義一個存放水果的數組:
const fruitsToGet = [“apple”, “grape”, “pear”];
循環遍歷這個數組:
const forLoop = async _ => { console.log('Start'); for (let index = 0; index < fruitsToGet.length; index++) { // 得到每個水果的數量 } console.log('End') }
在for
循環中,過上使用getNumFruit
來獲取每個水果的數量,并將數量打印到控制臺。
由于getNumFruit
返回一個promise
,我們使用 await
來等待結果的返回并打印它。
const forLoop = async _ => { console.log('start'); for (let index = 0; index < fruitsToGet.length; index ++) { const fruit = fruitsToGet[index]; const numFruit = await getNumFruit(fruit); console.log(numFruit); } console.log('End') }
當使用await
時,希望JavaScript暫停執行,直到等待 promise 返回處理結果。這意味著for
循環中的await
應該按順序執行。
結果正如你所預料的那樣。
“Start”; “Apple: 27”; “Grape: 0”; “Pear: 14”; “End”;
這種行為適用于大多數循環(比如while
和for-of
循環)…
但是它不能處理需要回調的循環,如forEach
、map
、filter
和reduce
。在接下來的幾節中,我們將研究await
如何影響forEach
、map和filter
。
首先,使用 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
始終返回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
時,希望篩選具有特定結果的數組。假設過濾數量大于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') }
如果想要計算 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
時,結果會變得非?;靵y。
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
?。?code>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
進行處理。
看完了這篇文章,相信你對JavaScript循環中怎么使用 async/await有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。