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 startsetTimeout被放在最后調用- 執行
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
