理解 async/await 的执行
這是一篇簡單的短文章,方便理解。
開局先丟官宣:sec-async-function-definitions?這個鏈接是對 await 的解釋,解釋了它的執行。
await 的執行意味著(官宣巴拉巴拉地說了14點,這里簡化成2點):
1. await 以 promise 形式完成,且 await 之后的代碼在 promise 被完成后以 .then 執行。
2. 遇到 await 時,將 async上下文 從上下文堆棧中移除,將上級(async之外)上下文(依次)恢復為當前執行的上下文;這步過程中需設置async上下文的評估狀態,以便在恢復到執行上下文時調用 await 之后的步驟。
第2點類似的理解為 async上下文 被掛起,依次向上運行上下文堆棧中的上下文代碼,完了后執行 async 函數里 await 之后的代碼。
估計看的繞,用代碼說話吧。
例一
console.log(1); async function async1(){ console.log(2); await async2(); console.log(3); };async function async2(){ console.log(4)};async1(); console.log(5);// 輸出結果 1 2 4 5 3理解一下輸出結果:
第一步:輸出 1;
第二步:輸出 2,async1 先被調用,肯定優先于函數內的console和后面的console.log(5);
第三步:輸出 4,把 await async2() 轉為 promise 形式:
new Promise(resolve => {console.log('2')resolve();}).then(res => {// 抽出 await 之后的代碼放到.thenconsole.log(3);});這時候先輸出 2,再等 3 的輸出。
但由于 3 在Promise規范里被設定為異步(劃重點: ES6中屬microTask ,此處直接影響低版本中對promise實現的shim ),且await表示遇到await關鍵字后先將這塊代碼的asyncContext掛起并執行上級上下文,所以先執行了5,于是...
第四步:輸出 5,執行完后回到 async context,再于是...
第五步:最后輸出 3。
例二
在官宣上沒看到? 依次向上??字樣鴨,咋肥事?繼續代碼:
console.log(1); function fn1(){function fn2(){async function async1(){ console.log(2);await fn3();console.log(3);}function fn3(){ console.log(4); }async1();new Promise(resolve => resolve(5)).then(res => console.log(res));console.log(6);}fn2();console.log(7); } fn1(); console.log(8); // 輸出結果 1 2 4 6 7 8 3 5理解一下輸出結果:
第一步:輸出 1;
第二步:fn1 被執行,fn2 被執行,輸出 2;
第三步:fn3 被執行,如第一例所述,輸出 4;
第四步:async context 被掛起,將 fn2 上下文作為運行上下文,輸出 6;
第五步:fn2 上下文處理后繼續向外更新,fn1 上下文作為運行上下文,輸出 7;
第六步:重復上述,輸出 8;
第七步:由于 fn3 的await(promise)在 fn2 中的 new Promise 前被加入執行列隊,根據先進先出的執行順序,輸出 3;
第八步:最后輸出 5。
例三
如果2個 async 嵌套順序是啥樣的呢?再看代碼:
console.log(1); function fn1(){async function fn2(){async function async1(){ console.log(2);await fn3();console.log(3);}function fn3(){ console.log(4); }await async1();new Promise(resolve => resolve(5)).then(res => console.log(res));console.log(6);}fn2();console.log(7); } fn1(); console.log(8); // 1 2 4 7 8 3 6 5重復上一個理解的過程,把 await async1(); 后的代碼放到最后執行,看做:
new Promise(resolve => {// async1 里的代碼 resolve(); }).then(res => {new Promise(resolve => resolve(5)).then(res => console.log(res));console.log(6); });對比以上輸出結果,正確!
如果有多個或者嵌套promise,則以??await 變成promise并掛起async上下文等上級上下文執行完后恢復? 和? 事件的執行順序遵循先進先出? 兩個規則去完成推斷執行順序。
注意
1. 在低版本瀏覽器中,async/await也有存在一些執行順序的偏差(或者根本就不支持);
2. 在ES6和ES5中promise的執行也有不同點(上述提到,ES6中promise屬microtask;在ES5中,暫未接觸到有api直接操作microtask的,所以.then的異步是用setTimeout代替,屬macrotask,導致輸出有差異);關于promise也可參考上文?分步理解 Promise 的實現
3. 由于客戶端環境不可控性太高,建議用于nodejs端開發。
彩蛋
通過上面的理解,再看下面的圖片(這是koa middleware的... 嘿嘿嘿):
?
希望這篇筆記能夠幫助前端袍澤們對async await的執行過程有更好的理解。上述內容僅供參考,如有理解不當的地方,還望提出!
總結
以上是生活随笔為你收集整理的理解 async/await 的执行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法62---最长回文子序列长度(子串)
- 下一篇: 如何用纯 CSS 创作一个精彩的彩虹 l