~先雙手奉上這道題目~promise
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');
JS衆所周知是單線程語言,Javascript引擎同一時刻只能執行一個代碼塊,使用Event Loop做爲它的異步執行機制瀏覽器
那麼Event Loop是如何實現異步呢,我的淺顯的理解以下:異步
等主進程中的同步函數執行完畢後,輪詢去執行異步隊列中的異步函數async
⚠️注意: setTimeOut並非直接的把你的回掉函數放進上述的異步隊列中去,而是在定時器的時間到了以後,把回掉函數放到執行異步隊列中去。若是此時這個隊列已經有不少任務了,那就排在他們的後面。這也就解釋了爲何setTimeOut爲何不能精準的執行的問題了。setTimeOut執行須要知足兩個條件:函數
1. 主進程必須是空閒的狀態,若是到時間了,主進程不空閒也不會執行你的回掉函數 2. 這個回掉函數須要等到插入異步隊列時前面的異步函數都執行完了,纔會執行
理解了Eventloop異步實現的方式,再來補充一下promise、async/awaitoop
首先,new Promise是同步的任務,會被放到主進程中去當即執行。而.then()函數是異步任務會放到異步隊列中去,那何時放到異步隊列中去呢?當你的promise狀態結束的時候,就會當即放進異步隊列中去了。若是你要問他和setTimeOut誰當進去的快,要從下面兩個方面考慮:線程
1. promise結束時。.then內函數插入異步隊列的時間與setTimeOut的回掉函數插入隊列的時間,誰的早,誰的就最快 2. **若是promise是同步的而setTimeOut時間是0,那麼是promise先執行**。至於什麼,查了不少的資料,瞭解到:一個瀏覽器環境只能有一個事件循環,而一個事件循環能夠有多個任務隊列。settimeout所在的隊列與promise.then()的隊列不一樣,面對此種狀況,v8實現的時候會先從promise.then()的隊列取任務,可是並無很理解,若是有大佬願意指點迷津,請留言告知🙏
接下來,帶着上面的那些總結,步入正題code
分析上述的代碼,給任務類型分類對象
async function async1() { console.log( 'async1 start’ ) // 同步代碼2 await async2() // 執行async2 console.log( 'async1 end’ ) // 須要等async1外面的代碼執行完,而且async2也執行完纔會執行 } async function async2() { console.log( 'async2’ ) // 同步代碼3 } // ===================== 從這裏開始了表演,因此在這裏走起 =============================== console.log( 'script start’ ) // 同步代碼1 setTimeout( function () { // setTimeout放入event-loop中的macro-tasks隊列,暫不執行 console.log( 'setTimeout' ) }, 0 ) async1() // 若是有await,第一個【await前面的代碼】屬於主進程執行—看最上面函數內分析 new Promise( function ( resolve ) { // 注意這個方法裏面的是同步 // 同步代碼4 console.log( 'promise1’ ) resolve(); } ).then( // .then()放入event-loop中的micro-tasks隊列 function () { console.log( 'promise2' ) } ) console.log( 'script end’ ) // 同步代碼5
最早輸出的是同步代碼,按照上下文執行順序是排序
'script start’ 'async1 start’ 'async2’ 'promise1’ 'script end’
第一個執行的函數是async1() ,裏面有await,他要等待,等待就是要讓async外面的代碼先執行,外面的那些同步代碼執行好了以後,在執行這個async裏面的,await後面的代碼執行。因此遇到await就讓出了線程,給到後面的代碼,那麼下面的promise.then
會先執行,後執行await後面的代碼
async1()的await後面和setTimeOut哪一個先執行,這個要看await等待的是什麼。此處等待的是async2函數,這個函數裏面沒有await等待,帶async
關鍵字的函數返回的是一個promise對象,因此async1中等待的是一個promise對象,而且這個promise對象裏面只有同步執行,會被放進時間循環的micro-tasks隊列,該隊列比setTimeOut的隊列先執行,執行完了以後還不能執行setTimeOut,由於執行完了以後就不阻塞主進程了,主進程要接着執行;也就是await後面的同步代碼,要先去執行主進程。因此setTimeOut是在最後執行的
再次驗證了上面所說的setTimeOut執行的必要條件之一是主進程空閒了
所以,異步代碼的執行順序是
‘promise2' // async函數外的代碼先執行 'async1 end’ // -- await不阻塞了,async後面的同步代碼 'setTimeout' // promise.then的隊列比setTimeout隊列先執行
若是你真正的理解了Event Loop的執行機制,而且知道setTimeout的與promise.then並不是一個隊列裏面的,那麼這道題就是很簡單的送分題
上述若有不足或者不當指出,請各位大佬匡正~~💗