forEach中的await
forEach中的await
不知道你是否寫過類似的代碼:
function test() {
let arr = [3, 2, 1]
arr.forEach(async item => {
const res = await fetch(item)
console.log(res)
})
console.log('end')
}
function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 500 * x)
})
}
test()
復制代碼
我當時期望的打印順序是
3
2
1
end
結(jié)果現(xiàn)實與我開了個玩笑,打印順序居然是
end
1
2
3
為什么?
復制代碼
其實原因很簡單,那就是 forEach 只支持同步代碼。
我們可以參考下 Polyfill 版本的 forEach,簡化以后類似就是這樣的偽代碼
while (index < arr.length) {
callback(item, index) //也就是我們傳入的回調(diào)函數(shù)
}
復制代碼
從上述代碼中我們可以發(fā)現(xiàn),forEach 只是簡單的執(zhí)行了下回調(diào)函數(shù)而已,并不會去處理異步的情況。并且你在 callback 中即使使用 break 也并不能結(jié)束遍歷。
怎么解決?
一般來說解決的辦法有2種,for...of和for循環(huán)。
使用 Promise.all 的方式行不行,答案是: 不行
async function test() {
let arr = [3, 2, 1]
await Promise.all(
arr.map(async item => {
const res = await fetch(item)
console.log(res)
})
)
console.log('end')
}
復制代碼
可以看到并沒有按照我們期望的輸出。
這樣可以生效的原因是 async 函數(shù)肯定會返回一個 Promise 對象,調(diào)用 map 以后返回值就是一個存放了 Promise 的數(shù)組了,這樣我們把數(shù)組傳入 Promise.all 中就可以解決問題了。但是這種方式其實并不能達成我們要的效果,如果你希望內(nèi)部的 fetch 是順序完成的,可以選擇第二種方式。
第1種方法是使用 for...of
async function test() {
let arr = [3, 2, 1]
for (const item of arr) {
const res = await fetch(item)
console.log(res)
}
console.log('end')
}
復制代碼
這種方式相比 Promise.all 要簡潔的多,并且也可以實現(xiàn)開頭我想要的輸出順序。
但是這時候你是否又多了一個疑問?為啥 for...of 內(nèi)部就能讓 await 生效呢。
因為 for...of 內(nèi)部處理的機制和 forEach 不同,forEach 是直接調(diào)用回調(diào)函數(shù),for...of 是通過迭代器的方式去遍歷。
async function test() {
let arr = [3, 2, 1]
const iterator = arr[Symbol.iterator]()
let res = iterator.next()
while (!res.done) {
const value = res.value
const res1 = await fetch(value)
console.log(res1)
res = iterator.next()
}
console.log('end')
}
復制代碼
第2種方法是使用 for循環(huán)
async function test() {
let arr = [3, 2, 1]
for (var i=0;i
const res = await fetch(arr[i])
console.log(res)
}
console.log('end')
}
function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 500 * x)
})
}
test()
復制代碼
第3種方法是使用 while循環(huán)
async function test() {
let arr = [3, 2, 1]
var i=0;
while(i!==arr.length){
const res = await fetch(arr[i])
console.log(res)
i++;
}
console.log('end')
}
function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 500 * x)
})
}
test()
復制代碼
要想在循環(huán)中使用async await,請使用for...of 或者 for 循環(huán), while循環(huán)
forEach支持async await
forEach 在正常情況像下面這么寫肯定是做不到同步的,程序不會等一個循環(huán)中的異步完成再進行下一個循環(huán)。原因很明顯,在上面的模擬中,while 循環(huán)只是簡單執(zhí)行了 callback,所以盡管 callback 內(nèi)使用了 await ,也只是影響到 callback 內(nèi)部。
arr.myforeach(async v => {
await fetch(v);
});
復制代碼
要支持上面這種寫法,只要稍微改一下就好
Array.prototype.myforeach = async function (fn, context = null) {
let index = 0;
let arr = this;
if (typeof fn !== 'function') {
throw new TypeError(fn + ' is not a function');
}
while (index < arr.length) {
if (index in arr) {
try {
await fn.call(context, arr[index], index, arr);
} catch (e) {
console.log(e);
}
}
index ++;
}
};

相關推薦HOT
更多>>
SEO優(yōu)化
SEO優(yōu)化,1、合理的title、description、keywords:搜索對著三項的權重逐個減小,title值強調(diào)重點即可;description把頁面內(nèi)容高度概括,不可過...詳情>>
2023-04-03 15:11:51
Python數(shù)據(jù)生產(chǎn)器
Python數(shù)據(jù)生產(chǎn)器,在軟件開發(fā)、測試或者數(shù)據(jù)分析過程中,有時候會需要一些測試數(shù)據(jù)。做測試的時候,需要模擬真實的環(huán)境,但是又不能直接使用真...詳情>>
2023-03-28 15:56:13
Java集合是什么?Java集合詳解
Java集合是Java編程語言中的一個重要概念,用于存儲、管理和處理數(shù)據(jù)。Java集合框架提供了一組接口和類,用于實現(xiàn)常見的數(shù)據(jù)結(jié)構,如列表、棧、...詳情>>
2023-03-20 19:12:47
js查找字符串中指定字符的位置
另外,如果要查找一個字符串中所有出現(xiàn)的指定字符的位置,可以使用indexOf()方法結(jié)合循環(huán)來實現(xiàn)。然后,我們使用循環(huán)遍歷字符串中的每一個字符...詳情>>
2023-03-10 14:06:35熱門推薦
forEach中的await
沸說說React中onClick綁定后的工作原理
熱小程序路由跳轉(zhuǎn)
熱說說gulp和webpack的區(qū)別
新跨域如何解決
SEO優(yōu)化
Null和undefined的區(qū)別
Python數(shù)據(jù)生產(chǎn)器
react中怎么實現(xiàn)vue中的計算屬性以及watch
經(jīng)典面試題:static加載機制你知道嗎?
消息中間件常用協(xié)議有哪些
Java集合是什么?Java集合詳解
線程池實現(xiàn)原理
java數(shù)據(jù)結(jié)構與算法
快速通道 更多>>
-
課程介紹
點擊獲取大綱 -
就業(yè)前景
查看就業(yè)薪資 -
學習費用
了解課程價格 -
優(yōu)惠活動
領取優(yōu)惠券 -
學習資源
領3000G教程 -
師資團隊
了解師資團隊 -
實戰(zhàn)項目
獲取項目源碼 -
開班地區(qū)
查看來校路線