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
複製代碼
結果現實與我開了個玩笑,打印順序竟然是bash
end
1
2
3
複製代碼
爲何?異步
其實緣由很簡單,那就是 forEach 只支持同步代碼。async
咱們能夠參考下 Polyfill 版本的 forEach,簡化之後相似就是這樣的僞代碼函數
while (index < arr.length) {
callback(item, index) //也就是咱們傳入的回調函數
}
複製代碼
從上述代碼中咱們能夠發現,forEach 只是簡單的執行了下回調函數而已,並不會去處理異步的狀況。 而且你在 callback 中即便使用 break 也並不能結束遍歷。post
怎麼解決?fetch
通常來講解決的辦法有2種,for...of和for循環。ui
使用 Promise.all 的方式行不行,答案是: 不行 spa
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')
}
複製代碼
能夠看到並無按照咱們指望的輸出。3d
這樣能夠生效的緣由是 async 函數確定會返回一個 Promise 對象,調用 map 之後返回值就是一個存放了 Promise 的數組了,這樣咱們把數組傳入 Promise.all 中就能夠解決問題了。可是這種方式其實並不能達成咱們要的效果,若是你但願內部的 fetch 是順序完成的,能夠選擇第二種方式。
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 要簡潔的多,而且也能夠實現開頭我想要的輸出順序。
可是這時候你是否又多了一個疑問?爲啥 for...of 內部就能讓 await 生效呢。
由於 for...of 內部處理的機制和 forEach 不一樣,forEach 是直接調用回調函數,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')
}
複製代碼
async function test() {
let arr = [3, 2, 1]
for (var i=0;i<arr.length;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()
複製代碼
參考連接: