如下代碼能夠用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
複製代碼