對於js任務隊列的理解

  • 這篇文章是我本身的一個學習總結,並非很是詳細,結合給出的連接能夠有更細緻的認識
  • 先介紹幾個概念,便於理解

關於堆和棧(做爲內存區域來講)

  • 堆(heap):存放object、array、function等不肯定內存大小的數據存儲;
  • 棧(stack):存放基本數據類型以及引用數據類型指向堆中的數據的指針,具備具體大小的數據結構,存取速度快;

調用棧(做爲一種代碼運行機制)

  • call stack(調用棧)指的是函數調用運行的機制,具體參考該連接:javascrip調用棧

事件循環機制(event loop)

參考:js事件循環機制javascript

  • 存在整個javascript腳本執行期間
  • 做用:將任務隊列的中能夠執行的函數壓入調用棧中

任務隊列(task queue)

任務隊列主要分爲兩種:html

  1. 宏任務(macro task):在新標準中叫taskhtml5

    宏任務主要包括:script(總體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
  2. 微任務(micro task):在新標準中叫jobsjava

    微任務主要包括:process.nextTick, Promise, Object.observe(已廢棄), MutationObserver(html5新特性)

以上提到的不僅有瀏覽器方法,還有nodejs的方法,這裏不具體說明了node

執行特色:

  • 每當調用棧爲空時,事件循環機制會將一個宏任務隊列中任務壓入調用棧中
  • 以空的調用棧爲起點的話,先執行全部宏任務,再執行全部微任務,而後調用棧又爲空,這樣一次能夠看做一個單元,以後就是一直在循環執行這樣單元

分解執行過程:segmentfault

  1. 執行全部調用棧中的宏任務
  2. 宏任務執行過程當中產生的微任務加入到微任務隊列
  3. 宏任務執行完馬上執行全部微任務隊列中的任務
  4. 以上執行完畢,檢查渲染,GUI線程接管渲染
  5. 渲染完畢後,js線程接管,開啓下一次事件循環(每一次事件循環(script不包括),只處理一個宏任務),執行下一次宏任務(任務隊列中取)

很差理解的地方瀏覽器

  • 以上過程(不管宏任務仍是微任務執行)中產生的宏任務進入宏任務隊列等待,進入後面的循環執行,不在當次循環中被執行
  • 可是以上過程當中(包括微任務)產生的微任務又會被馬上放到當次循環的微任務隊列後面按順序執行

以上兩句可能有點繞,能夠參考上面循環機制的連接,有相關圖解。數據結構

換個說法:微任務優先於當前調用棧產生的宏任務被執行函數

若是能理解下面這段代碼的執行過程應該就基本理解任務隊列的執行過程了:oop

setTimeout(() => {
    console.log('1')

    new Promise((resolve) => {
        resolve()
    }).then(() => {
        console.log('2')
    })
}, 0);

setTimeout(() => {
    console.log('3')
}, 0);

new Promise((resolve) => {
    resolve()
}).then(() => {
    console.log('4')

    new Promise((resolve) => {
        resolve()
    }).then(() => {
        console.log('5')
    })

    setTimeout(() => {
        console.log('6')
    }, 0);
})

new Promise((resolve) => {
    resolve()
}).then(() => {
    console.log('7')
})

// 輸出順序爲: 4,7,5,1,2,3,6
相關文章
相關標籤/搜索