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 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
作者:心譚
鏈接:https://www.jianshu.com/p/5938d9fdbccd
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
