用promise理解async、await

先用promise理解一遍

如下代碼能夠用promise更好理解promise

async function a(){
    console.log(1)
    const w = await v
    console.log(3)
    return w
}
a()
console.log(2)
複製代碼

相似於bash

先入棧執行a():
    console.log(1)
遇到await v,假設v不是function,則後面都用promise包起來:
    假設v是一個基本類型
    finalPromise = Promise.resolve(v).then((res)=>{console.log(3);return res}) 
    若v是一個promise
    finalPromise = v.then((res)=>{console.log(3);return res})
而後扔出去給處理promise的線程執行:
    return Promise.resolve(finalPromise)
扔出去後函數a出棧,繼續執行:
    console.log(2)
promise由其餘線程執行,resolve後回調進入微任務堆棧,這已是主線程以後的任務了:
    console.log(3)
    return res
複製代碼

注意:v8裏面碰到await這一步說是suspend延遲,當v被resolve的時候會resume恢復到當前做用域那一步執行,我本身也不太懂裏面的具體實現,這邊這樣理解若是有誤但願指正異步

拋出問題

每次在使用async和await的時候,尤爲在使用forEach、有多個await的時候,對哪一個先執行很是混亂,但願可以理清楚。async

解決問題

reference:Faster async functions and promises函數

先看v8解釋圖:微服務

左邊是原始代碼,右邊是解釋後的代碼。ui

接下來跟作數學題同樣,首先定義幾個定理:spa

定理

定理一、Promise.resolve(promise) === promise爲真線程

這個是根據下面promiseResolve這個函數得出的,圖在下面
複製代碼

定理二、async函數返回一個promise3d

因爲函數v8的簡易解釋圖最後沒有return的操做,因此實現應該不太一致
但這必定是正確的哈!!!
返回的應該是函數最後的 resolvePromise(implicit_promise, w)
相似於 return Promise.resolve(w)
複製代碼

定理三、await v 相似於 Promise.resolve(v)

根據v8圖裏面的: promise = promiseResolve(v) 
若是v不是一個promise:
    await v 相似於 Promise.resolve(v)會建立一個promise
若是v是一個promise:
    根據定理1,返會的就直接是v這個promise
複製代碼

定理四、await後面是function的話是會先執行function的

遇到函數都會先入棧執行吧?
複製代碼

定理五、await所在做用域的await後面的代碼,其執行時間都是在這個await返回的promise被resolve後,能夠理解成放在then裏面

官方是suspend、resume這種實現的,理解成放在這個promise的then裏面若是有問題但願及時指正
async function a(){
    console.log(1)
    const w = await v
    console.log(3)
    return w
}
根據定理二、3相似於
function a(){
    console.log(1)
    return Promise.resolve(
        Promise.resolve(v).then((res)=>{console.log(3);return res})
    )
}
根據定理1等價於
function a(){
    console.log(1)
    return Promise.resolve(v).then((res)=>{console.log(3);return res})
}
若是v是一個promise的話根據定理1等價於
function a(){
    console.log(1)
    return v.then((res)=>{console.log(3);return res})
}
複製代碼

簡易理解版

遇到await,當前做用域以後的代碼執行若是不是function就都包起來扔出去等待異步執行,而後繼續執行同步代碼

再加一個例子

const a=async (index)=>{
    console.log("a0"+index)
    await console.log("a1"+index)
    console.log("a2"+index)
}

async function example () {
  const nums = [2,2] 

  nums.forEach(async (num,index) => {
    console.log(`forEach${index}`)
    const b = await a(index)
    console.log(index)
  })
  console.log('out')
}

example()
console.log('example finished')
複製代碼

相似於

example進棧執行,forEach執行:
    console.log('forEach0')
遇到await,await後面是function,入棧執行a():
    console.log("a00")
又發現await且後面是函數,執行console.log:
    console.log("a10"),返回undefined
變成await undefined,因而將其做用域後面的代碼打包起來扔出去:
    return promiseA = Promise.resolve(undefined).then(()=>{console.log("a2")})
    扔出去等待異步執行
a出棧,返回的是promiseA,在example中變成await promiseA:
    return promiseB = promiseA.then(()=>{console.log(b)})
    打包起來扔出去等待異步執行
第一個forEach函數出棧,第二個入棧(forEach是同步過程):
    重複上面幾個步驟,假設最終是promiseC被扔出去 
第二個forEach函數出棧,example出棧:
    執行console.log('example finished')
主程序完成,清空微服務棧:
    第一個forEach的promise chain(promiseB)的頭部仍是第二個(promiseC)的頭部先被resolve?
    由於這邊的都是當即resolve的
    所以promiseB的then回調B一、promiseC的then回調C1前後被加入隊列
    執行B1的console.log("a20")
    執行完返回一個被resolve的promise因而其then回調B2加入微服務隊列尾部
    執行C1的console.log("a21")
    執行完返回一個被resolve的promise因而其then回調C2加入微服務隊列尾部
    執行B2的then的回調的console.log(0)
    執行C2的then的回調的console.log(1)

最終結果
forEach0
a00
a10
forEach2
a01
a11
out
example finished
a20
a21
0
1
複製代碼
相關文章
相關標籤/搜索