1. 程式人生 > >事件迴圈進階:macrotask與microtask

事件迴圈進階:macrotask與microtask

這段參考了參考來源中的第2篇文章(英文版的),(加了下自己的理解重新描述了下),

這裡沒法給大家演示程式碼,我就簡單說下我的理解吧。

 

promise和settimeout 在一起的時候執行順序是個有意思的事兒,

 

為什麼呢?因為Promise裡有了一個一個新的概念:microtask

或者,進一步,JS中分為兩種任務型別:macrotaskmicrotask,在ECMAScript中,microtask稱為jobs,macrotask可稱為task

 

它們的定義?區別?簡單點可以按如下理解:

  • macrotask(又稱之為巨集任務),可以理解是每次執行棧執行的程式碼就是一個巨集任務(包括每次從事件佇列中獲取一個事件回撥並放到執行棧中執行)

    • 每一個task會從頭到尾將這個任務執行完畢,不會執行其它

    • 瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執行,會在一個task執行結束後,在下一個 task 執行開始前,對頁面進行重新渲染

(`task->渲染->task->...`)

 

  • microtask(又稱為微任務),可以理解是在當前 task 執行結束後立即執行的任務

    • 也就是說,在當前task任務後,下一個task之前,在渲染之前

    • 所以它的響應速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染

    • 也就是說,在某一個macrotask執行完後,就會將在它執行期間產生的所有microtask都執行完畢(在渲染前)

 

分別很麼樣的場景會形成macrotask和microtask呢?

  • macrotask:主程式碼塊,setTimeout,setInterval等(可以看到,事件佇列中的每一個事件都是一個macrotask)

  • microtask:Promise,process.nextTick等

__補充:在node環境下,process.nextTick的優先順序高於Promise__,也就是可以簡單理解為:在巨集任務結束後會先執行微任務佇列中的nextTickQueue部分,然後才會執行微任務中的Promise部分。

 

再根據執行緒來理解下:

    • macrotask中的事件都是放在一個事件佇列中的,而這個佇列由事件觸發執行緒維護

    • microtask中的所有微任務都是新增到微任務佇列(Job Queues)中,等待當前macrotask執行完畢後執行,而這個佇列由JS引擎執行緒維護(這點由自己理解+推測得出,因為它是在主執行緒下無縫執行的)

 

所以,總結下執行機制:

    • 執行一個巨集任務(棧中沒有就從事件佇列中獲取)

    • 執行過程中如果遇到微任務,就將它新增到微任務的任務佇列中

    • 巨集任務執行完畢後,立即執行當前微任務佇列中的所有微任務(依次執行)

    • 當前巨集任務執行完畢,開始檢查渲染,然後GUI執行緒接管渲染

    • 渲染完畢後,JS執行緒繼續接管,開始下一個巨集任務(從事件佇列中獲取)

  • 另外,請注意下Promisepolyfill與官方版本的區別:

    • 官方版本中,是標準的microtask形式

    • polyfill,一般都是通過setTimeout模擬的,所以是macrotask形式

    • 請特別注意這兩點區別

    注意,有一些瀏覽器執行結果不一樣(因為它們可能把microtask當成macrotask來執行了),
    但是為了簡單,這裡不描述一些不標準的瀏覽器下的場景(但記住,有些瀏覽器可能並不標準)

 

好了,到這裡咱們這個從瀏覽器到多程序到多執行緒到js單執行緒到js執行機制就講完了。內容還算是比較全面,不足的就是隻能聽麼有程式碼參考。

不過沒關係,大家可以根據我提到的知識點自己再進行深入的學習,或者關注下我個人的公眾號-重度前端,我講的內容都有文字版在上面而且有程式碼,另外我記錄了一些我平時看到的比較好的 有深度的文章,還有一些原創內容。直接微信 搜 重度前端。 

 

好了,今天就到這裡了。後面計劃下分享哪些有意思的東西,咱們下次見。