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
之后輸出
在函數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
4、參考
歡迎技術交流,引用請注明出處。
個人網站:godbmw.com
Github:godbmw