大體問題是:
經過map或者foreach循環的回調函數操做數組,回調函數內部有ajax異步函數,經過await同步的寫法來調用的。console.log打印出數組跟實際渲染到view層的頁面始終不一致。
後來改寫成for循環就行了。ajax
第一次發現bug覺得是雙向綁定出現了問題,由於數組會有此狀況。但後來排除了。api
第二次發現是隻要經過await調用了異步方法,後面同步代碼再執行await後返回的結果,就會出現bug。數組
第三次。。。隱藏各類代碼,還懷疑是阿里雲的sdk出現了問題。
後來找老大才解決了這個問題,雖然上廁所期間也感受就是map或foreach方法的回調函數出現了問題,但不知道從何改也想過使用for循環改造,but須要在for循環內部使用await關鍵字,考慮可能會報錯。異步
因此總結出來,基礎知識,在理解map和foreach這個api不夠深入,也對await 關鍵詞的使用場景理解不透徹(雖然是for循環,但做用域函數能夠找到頂層的函數做用域,因此不會報錯)async
貼出代碼:函數
錯誤代碼oop
adBannerList.map(async (item) => { // 異步函數 轉同步的寫法 let res = await this.getAliyunAds(); // 異步函數執行成功後,改變此數組的值 item.imageUrl = res.imgUrl; item.linkUrl = res.actUrl; }) // map 循環結束後,再執行雙向綁定 this.setData({ bannerList: adBannerList, }); console.log('bannerList', this.data.bannerList)
指望結果是map循環結束後,纔會執行雙向綁定setData函數。
實際結果是:還未等map循環完(還未等內部的await 後面的異步函數執行完),setData 就執行了。
此時console.log 數組所看見的結果,跟view渲染呈現的結果不一致。
這裏須要去深刻理解下,引用類型和簡單類型的console.log,以及console.log的機制。
推薦看這篇文章:console.log碰見的坑this
正確代碼:阿里雲
for(let i = 0;i < adBannerList.length; i++) { let item = adBannerList[i] // 這裏await關鍵詞能夠用是由於for循環內部沒函數做用域, //因此會向上找函數做用域,只要有async就能夠。 let res = await this.getAliyunAds(); item.imageUrl = res.imgUrl; item.linkUrl = res.actUrl; } this.setData({ bannerList: adBannerList, });
知識點總結:
1.map和foreach(應該還有更多的相似函數)的回調函數是一個同步函數,非異步函數。.net
須要升入的知識點:
一、console.log的機制。尤爲是針對引用類型
二、async await使用場景?在何時會失效?
三、類型map和foreach 這樣的循環函數機制。
我後來又從新去作了一個demo,發現問題的所在點多是:
回調函數內部有ajax異步函數,經過await同步的寫法來調用的
重點就是:await 後面執行的函數是ajax異步函數。
那若是await後面執行的函數是setTimeout 函數呢?
貼代碼:
function test () { return new Promise((resolve, reject) => { setTimeout(() => { console.log('-----') }, 3000) }) } function async lnk() { for(let i = 0; i < arr.length; i++ ){ await test() } console.log('arr', arr) } lnk()
按照剛纔的理解,for循環內部執行await方法,按理是應該阻塞執行,等待異步執行後,再執行同步console.log('arr', arr)方法。但實際是:先執行了打印arr,而後3秒後執行的test內部方法。一樣看似形成了await的「失效」我如今完全懵逼了,得去惡補下eventloop的知識點了。不太重點應該仍是await--async 這一堆api理解不夠。