天天看點

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

    單線程任務被分為同步任務和異步任務,同步任務會在調用棧中按照順序等待主線程依次執行,異步任務會在異步任務有了結果後,将注冊的回調函數放入任務隊列中等待主線程空閑的時候(調用棧被清空),被讀取到棧内等待主線程的執行。
setTimeout、Promise、Async/Await 的執行順序
setTimeout、Promise、Async/Await 的執行順序

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版本)

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

(73及以上版本執行結果為)

script start
async1 start
async2
promise1
script end
async1 end promise2 setTimeout      

轉載于:https://www.cnblogs.com/dajuyiding/p/11355677.html

繼續閱讀