Javascript 有一個 main thread 主線程和 call-stack 調用棧(執行棧),所有的任務都會被放到調用棧等待主線程執行。 JS調用棧採用的是後進先出的規則,當函數執行的時候,會被添加到棧的頂部,當執行棧執行完成後,就會從棧頂移出,直到棧內被清空。 Javascript單線程 ...
問題描述:以下這段代碼的執行結果
async function async1() { console.log('async1 start'); await async2(); console.log('asnyc1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(() => { console.log('setTimeOut'); }, 0); async1(); new Promise(function (reslove) { console.log('promise1'); reslove(); }).then(function () { console.log('promise2'); }) console.log('script end');
解決問題:
要瞭解代碼的執行順序 必須先瞭解 JS的運行機制
Javascript
有一個main thread
主線程和call-stack
調用棧(執行棧),所有的任務都會被放到調用棧等待主線程執行。- JS調用棧採用的是後進先出的規則,當函數執行的時候,會被添加到棧的頂部,當執行棧執行完成後,就會從棧頂移出,直到棧內被清空。
Javascript
單線程任務被分為同步任務和非同步任務,同步任務會在調用棧中按照順序等待主線程依次執行,非同步任務會在非同步任務有了結果後,將註冊的回調函數放入任務隊列中等待主線程空閑的時候(調用棧被清空),被讀取到棧內等待主線程的執行。
在JavaScript
中,任務被分為兩種,一種巨集任務(MacroTask
),一種叫微任務(MicroTask
)。
MacroTask(巨集任務)
script
全部代碼、setTimeout
、setInterval
。
MicroTask(微任務)
Promise、await
每次單個巨集任務執行完畢後,檢查微任務隊列是否為空,如果不為空的話,會按照先入先出的規則全部執行完微任務後,設置微任務隊列為
null
,然後再執行巨集任務,如此迴圈。
運行之前我們需要知道以下幾點
- setTimeout屬於巨集任務
- Promise本身是同步的立即執行函數,Promise.then屬於微任務
- async方法執行時,遇到await會立即執行表達式,表達式之後的代碼放到微任務執行
下麵我們就來運行代碼
第一次執行:執行同步代碼
Tasks(巨集任務):run script、 setTimeout callback
Microtasks(微任務):await、Promise then
JS stack(執行棧): script
Log: script start、async1 start、async2、promise1、script end
第二次執行:執行巨集任務後,檢測到微任務隊列中不為空、一次性執行完所有微任務
Tasks(巨集任務):run script、 setTimeout callback
Microtasks(微任務):null
JS stack(執行棧): await、Promise then
Log: script start、async1 start、async2、promise1、script end、promise2、async1 end
第三次執行:當微任務隊列中為空時,執行巨集任務,執行setTimeout callback
,列印日誌。
Tasks(巨集任務):null Microtasks(微任務):null JS stack(執行棧):setTimeout callback
Log: script start、async1 start、async2、promise1、script end、promise2、async1 end、setTimeout
關於73以下版本和73版本的區別
- 在老版本版本以下,先執行
promise2
,再執行async1 end
。 - 在73及以上版本,先執行
async1 end
再執行promise2
。 - 具體資料可以查詢 https://v8.js.cn/blog/fast-async/
於是我們就得到了這段代碼的執行結果(70版本)
(73及以上版本執行結果為)
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout