1. 程式人生 > 其它 >js的微任務和巨集任務

js的微任務和巨集任務

一、任務佇列

弄清楚這個概念要先明白什麼是任務:

一個任務就是指計劃由標準機制來執行的任何 JavaScript,如程式的初始化、事件觸發的回撥等。

除了使用事件,你還可以使用setTimeout()或者setInterval()來新增任務

所謂任務,淺顯來說就是程式碼塊開始執行的入口(確切地說,是函式棧的入口

二、非同步是怎麼實現的event loop迴圈

主執行緒發起如果一個非同步請求,相應的工作執行緒就接收這個請求並進行處理,期間,主執行緒發完請求之後就去幹別的事情去了。等到工作執行緒的處理有了結果,瀏覽器內部就分配一個執行緒(event table)出來,通知主執行緒,剛剛發起的非同步請求有了結果(這個通知過程其實是將回調函式推入訊息佇列(event queue)中,也叫事件佇列,也叫任務佇列),等到主執行緒處理完了當前呼叫棧中的任務,就會從這個訊息佇列中讀取訊息,也就是呼叫回撥。這樣就完成了一次非同步操作。

而javascript執行程式碼的機制就是不斷地從判斷主執行緒是否為空,為空就讀取訊息佇列(event queue)的回撥並執行的過程。

我的理解:執行js程式碼的時候會判斷程式碼是同步還是非同步,同步進入主執行緒執行,非同步進入event table執行。非同步執行完後會將其回撥函式註冊進入event queue(微任務和巨集任務不是同一個event queue)。js會檢測主執行緒是否還有程式碼執行,如果執行完就去檢視event queue中是否有已經註冊了的函式,如果有就執行。沒有就判斷主執行緒是否為空。為空就判斷訊息佇列(event queue),迴圈往復。

三、微任務和巨集任務

巨集任務(macrotask)

可以理解是每次訊息佇列執行的程式碼就是一個巨集任務(包括每次從事件佇列中獲取一個事件回撥並放到訊息佇列中執行)。

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

進入任務棧等待主執行緒執行的主程式碼塊,包括從非同步佇列里加入到棧的,如setTimeout()、setInterval()的回撥,其中不含非同步佇列中的微任務如Promise.then回撥。

微任務(microtask)

是非同步佇列中,在當前這一次巨集任務執行完後,頁面渲染之前要執行的任務。

此時注意,即使當前微任務執行過程中,產生了新的微任務,也會在下一個巨集任務開始執行之前且當前事件迴圈結束之前執行完所有的微任務。

注意:

1.微任務是用於插隊的

2.微任務是快於巨集任務的,但是一般是由巨集任務(<script>)開始執行。

3.微任務>dom渲染>巨集任務

1)main script中的程式碼優先執行(編寫的頂層script程式碼);
2)在執行任何一個巨集任務之前(不是佇列,是一個巨集任務),都會先檢視微任務佇列中是否有任務需要執行
3)也就是巨集任務執行之前,必須保證微任務佇列是空的;
4) 如果不為空,那麼久優先執行微任務佇列中的任務(回撥)

巨集任務一般是:包括整體程式碼script,setTimeout,setInterval。

微任務:Promise,process.nextTick。

非同步任務分為巨集任務和微任務。

<script>標籤可以理解為一個巨集任務,因為這是一個程式碼段的入口,且必須要先載入。 排前面的 script 先執行,執行其內部的【同】,再執行其【微】,接著就輪到下一個大的巨集,也就是執行下一個 script,【同】、【微】。。。順序執行完後,再從頭開始,看第一個 script 是否有需要執行的【巨集】,再去下一個 script 中找 【巨集】,等大家巨集結束後,進入下一輪迴圈。

1.,巨集任務和微任務的執行時間

前四行程式碼會給網頁增加一個結構和內容,可以幫我們判斷渲染和巨集任務、微任務的前後。

最開渲染沒有出現的原因:

文件解析 和 頁面渲染 是兩個不同的概念

瀏覽器開啟一個網頁的過程是: 載入一部分程式碼 >>> 文件解析(如有js則立即執行) >>> 頁面渲染 >>> 載入下一部分程式碼 >>> 文件解析 >>> 頁面渲染 .......

文件解析 是根據html程式碼在系統記憶體中建立Dom元素,這時Dom元素只是在記憶體中,你在這之後可以用js訪問之前已經解析了的Dom元素。但卻不會立即繪製到頁面上。 直到 頁面渲染 時才會把記憶體中的Dom元素繪製到頁面上。

而微任務是先於dom渲染的所以在執行promise的任務時,頁面沒有渲染。

巨集任務的執行是在dom渲染後,所以頁面會出現文字內容。

2.微任務與巨集任務的區別

這個就像去銀行辦業務一樣,先要取號進行排號。
一般上邊都會印著類似:“您的號碼為XX,前邊還有XX人。”之類的字樣。

因為櫃員同時職能處理一個來辦理業務的客戶,這時每一個來辦理業務的人就可以認為是銀行櫃員的一個巨集任務來存在的,當櫃員處理完當前客戶的問題以後,選擇接待下一位,廣播報號,也就是下一個巨集任務的開始。
所以多個巨集任務合在一起就可以認為說有一個任務佇列在這,裡邊是當前銀行中所有排號的客戶。
任務佇列中的都是已經完成的非同步操作,而不是說註冊一個非同步任務就會被放在這個任務佇列中,就像在銀行中排號,如果叫到你的時候你不在,那麼你當前的號牌就作廢了,櫃員會選擇直接跳過進行下一個客戶的業務處理,等你回來以後還需要重新取號

而且一個巨集任務在執行的過程中,是可以新增一些微任務的,就像在櫃檯辦理業務,你前邊的一位老大爺可能在存款,在存款這個業務辦理完以後,櫃員會問老大爺還有沒有其他需要辦理的業務,這時老大爺想了一下:“最近P2P爆雷有點兒多,是不是要選擇穩一些的理財呢”,然後告訴櫃員說,要辦一些理財的業務,這時候櫃員肯定不能告訴老大爺說:“您再上後邊取個號去,重新排隊”。
所以本來快輪到你來辦理業務,會因為老大爺臨時新增的“理財業務”而往後推。
也許老大爺在辦完理財以後還想再辦一個信用卡?或者再買點兒紀念幣
無論是什麼需求,只要是櫃員能夠幫她辦理的,都會在處理你的業務之前來做這些事情,這些都可以認為是微任務。

這就說明:你大爺永遠是你大爺
在當前的微任務沒有執行完成時,是不會執行下一個巨集任務的。

引用:微任務、巨集任務與Event-Loop - 賈順名 - 部落格園 (cnblogs.com)