setTimeout、Promise、Async/Await 的執行順序


問題描述:以下這段代碼的執行結果
    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全部代碼、setTimeoutsetInterval

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 endpromise2、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
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM