1、題目和答案
一道題題目:下面這段promise、async和await代碼,請問控制台打印的順序?
async function async1(){ console.log('async1 start') await async2() console.log('async1 end') } async function async2(){ console.log('async2') } console.log('script start') setTimeout(function(){ console.log('setTimeout') },0) async1(); new Promise(function(resolve){ console.log('promise1') resolve(); }).then(function(){ console.log('promise2') }) console.log('script end')
上述,在Chrome 66
和node v10
中,正確輸出是:
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
2、知識點
顯然,這考察的是js中的事件循環和回調隊列。注意以下幾點:
Promise優先於setTimeout宏任務。所以,setTimeout回調會在最后執行。
Promise一旦被定義,就會立即執行。
Promise的reject和resolve是異步執行的回調。所以,resolve()會被放到回調隊列中,在主函數執行完和setTimeout前調用。
await執行完后,會讓出線程。async標記的函數會返回一個Promise對象
3、 難點
最令人困惑的,就是
async1 end
在promise2
之后輸出
async 函數中可能會有 await 表達式,這會使 async 函數暫停執行,將await的結果封裝成一個Promise,並等待解析完成后繼續執行, 另外如果await 遇上async函數,阮一峰老師這么說明: async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操作完成,再接着執行函數體內后面的語句。
在函數async1
中,執行promise
(由於async2
是async
標記的函數,所以默認返回promise
對象)會發現resolve()
,然后放入回調隊列。
接着執行下方的new Promise
中的resolve()
輸出promise2
,再回來輸出async1 end
。
其中,async1
函數可以寫成以下方式(便於理解):
async function async1(){ console.log('async1 start') async2().then( _ => { console.log( 'async1 end ') }) }
3、流程
console.log('script start')
輸出:script start
setTimeout
被放在最后調用- 執行
async1
函數,輸出async1 start
。然后,進入async2
函數,輸出async2
,並返回Promise
對象。回到async1
,由於await
,讓出線程,async2
函數返回的Promise
放在回調隊列。 - 新new了一個
Promise
對象,輸出promise1
。其中的resolve()
被放在回調隊列。 console.log('script end')
輸出:script end
- 執行回調隊列中,
async1
返回的Promise
對象,對象產生的resolve
被放入對調隊列。這里不輸出任何值。 - 執行回調隊列中,下方
Promise
顯式聲明的resolve
,輸出promise2
。 - 執行回調隊列中,由於
async1
函數返回的promise
對象的resolve
,輸出async1 end
。 - 執行回調隊列中,最后的
setTimeout
,輸出setTimeout
- finish
作者:心譚
鏈接:https://www.jianshu.com/p/5938d9fdbccd
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。