javascript異步解決方案簡介及數(shù)組遍歷中async用法

我們知道,javascript是單線程的,任務(wù)只能依次排開,,挨個執(zhí)行,但是為了完成某些并行的需求,類似網(wǎng)絡(luò)請求(網(wǎng)絡(luò)請求有單獨的線程去處理),就必須引入異步的概念,簡單來理解就是:我想要吃飯,但是做好飯需要十分鐘,這十分鐘我不能待著,我要玩手機,等飯做好了,我再繼續(xù)吃飯。

最傳統(tǒng)普遍的異步解決方案就是寫回調(diào)函數(shù),

定時器

setTimeout(function(){
    console.log("開始吃飯")
},600000)

網(wǎng)絡(luò)請求

$post("www.chifan.com",function(res){
    console.log("吃飯")
})

這會產(chǎn)生幾個問題
回調(diào)地獄,難處理的異常,非常不優(yōu)雅的代碼。。

隨著前端應(yīng)用復(fù)雜性的不斷提升,回調(diào)函數(shù)越來越不能滿足我們的需求,幾種解決方案被提了出來,
Promise,Generator,async/await

Promise

new Promise(function(resolve,reject){
    if("做好飯"){
        resolve("飯好了")
    }
    else{
        reject("飯糊了")
    }
})
.then(res=>{
    console.log("吃飯")
})
.catch(err=>{
    console.log("吃不成了")
})

Generator

function* chifan(){
    yeild 'chifan'
}
new chifan().next()

async/await

async function(){
    await zuofan();
    return "吃飯了"
}

下面我們著重來介紹下promise,因為promise + async await 是業(yè)界異步解決方案最優(yōu)雅的解法了,大約只有c# 和 nodejs 原生實現(xiàn)了此特性

我們先看下PromiseA+規(guī)范

  • "promise"是一個函數(shù),攜帶有滿足規(guī)范的then方法
  • "promise" 有三種狀態(tài),pending,onFulfilledonRejected,且從pending只能切換到onFulfilled或者onRejected一種狀態(tài),不能切換
  • then方法返回的也是promise,且可以鏈?zhǔn)秸{(diào)用

看懂了規(guī)范我們先來演示一下在promise 和 async await下我們?nèi)绾谓鉀Q異步問題。

比如我們想要在兩秒之后打印吃飯,吃完飯三秒后打印睡覺,傳統(tǒng)回調(diào)寫法

setTimeout(function(){
    console.log('吃飯');
    setTimeout(function(){
        console.log('睡覺')
    },3000)
},2000)

promise 寫法

new Promise(function(res,rej){
    setTimeout(function(){
        console.log("吃飯")
        res()
    },2000)
})
.then(res=>{
    return new Promise(function(res,rej){
         setTimeout(function(){
               console.log("睡覺")
              res()
        },3000)
    })
})
.then(res=>{

},
reject=>{
  console.log("異常")
})
.catch(err=>{
    console.log(err)
})

async await 寫法

(async function(){
    await new Promise(function(res,rej){
      setTimeout(function(){
          console.log("吃飯")
          res()
      },2000)
    })

  await new Promise(function(res,rej){
         setTimeout(function(){
               console.log("睡覺")
              res()
        },3000)
    })
})()

是不是感覺越寫越像同步呢。
async 關(guān)鍵字用于匿名函數(shù)前面或者函數(shù)名字前面,有了這個關(guān)鍵字,函數(shù)內(nèi)部可以使用await關(guān)鍵字,await關(guān)鍵字后面跟著一個promise對象,可以是函數(shù)返回一個promsie對象或者new 的一個promise對象,而每個await對應(yīng)promise之后的代碼,都會在當(dāng)前await對應(yīng)的promise resolve 之后才會執(zhí)行,相當(dāng)于將當(dāng)前await 對應(yīng)promise之后的代碼包裹到了then 之中執(zhí)行,,然后如果又碰到await。還是同理,一層層包裹,保證了多個await 對應(yīng)promise的順序執(zhí)行

現(xiàn)在async中的代碼可以順序執(zhí)行了,但是當(dāng)前加了async 關(guān)鍵字的函數(shù)還是無法保證其他的函數(shù)在此函數(shù)執(zhí)行完之后執(zhí)行,因為瀏覽器的事件循環(huán)機制中,promise是放在微任務(wù)隊列中執(zhí)行的,,
因此,async 函數(shù)的返回值也是一個promise,無法保證當(dāng)前async 函數(shù)后面的函數(shù)在此函數(shù)所有內(nèi)容執(zhí)行完之后執(zhí)行,如果多個async 函數(shù)并行執(zhí)行,我們還是需要將它當(dāng)成promsie 進行處理。

也就是說 async 的返回值是一個promise

這時候如果我們在es5 提供的數(shù)組的遍歷函數(shù)中使用async await 會產(chǎn)生一些難以預(yù)料的問題,如果你對async await promise 非常了解了,可以在 forEach,mapfilter等中使用,類似這種

    [1,2,3].map(async _=>{
        await new Promise();
        return _+1
   })

    // 執(zhí)行其他代碼 

這個時候的函數(shù)執(zhí)行時序會有些復(fù)雜,如果你理解了本文,可以預(yù)見到執(zhí)行的結(jié)果,

如果你不是非常明白他的執(zhí)行時序,建議遇到循環(huán)時,還是乖乖的寫for循環(huán)吧。。。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容