forEach與async/await使用踩坑


function test() {
 let arr = [1, 2, 3]
 arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}
 
function fetch(x) {
 return new Promise((resolve, reject) => {
     resolve(x)
 })
}
 
test()

思考如上代碼、我們預期結果是先輸出1,2,3,然后因為等待異步結果最后輸出end

但是實際上輸出卻是end先輸出,才到1,2,3。

原因如下:

1、首先這是因為foreach是沒有return返回值的(可以自己去跟下源碼,foreach內部實現只是簡單的回調)

2、而foreach里面的回調函數因為加了async的原因,所以默認會返回一個promise,但是因為foreach的實現並沒有返回值,所以導致返回的這個promise對象沒人去管了

 

首先為了保證end最后輸出,我們肯定要先等待循環的返回結果因此改成如下代碼

async function test() {
 let arr = [1, 2, 3]
 await arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}

但是這樣改之后依然行不通,原因是foreach沒有返回值,所以我們必須保證循環能夠有返回值,所以要將foreach改成map

async function test() {
 let arr = [1, 2, 3]
 await arr.map(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}

結果依然不行,然后我們會發現其實map返回的並不是一個promise對象,而是一個包含promise對象的數組[promise, promise, promise],其中每個promise對象都是循環迭代產生的結果。而await是處理不了數組的,它只能處理promise對象。考慮到這一點我們基本上就差不多知道如何改正了、有兩種方法。

第一是將循環改成常規的遍歷方式

async function test() {
 let arr = [1, 2, 3]
 for(let i in arr){
   const res = await fetch(arr[i])
   console.log(res)              
 }
 console.log('end')
}

第二種就比較高端了,使用Promise.all(),這是一個專門處理promise數組的方法,當async標記的箭頭函數返回一個promise對象時,map方法得到的就是一個promise對象數組,然后我們將這個數組丟給Promise.all()去依次執行,然后只需要使用await去等待執行結果,就能保證后面的end在得到結果后才會被輸出,得到最終輸出結果1,2,3,end

async function test() {
 let arr = [1, 2, 3]
 await Promise.all(arr.map(async item => {
  const res = await fetch(item)
  console.log(res)
 }))
 console.log('end')
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM