JS事件循環與宏任務-微任務

其實關於JS的事件循環,自己之前是有部分了解的,但是這個瞭解還不夠詳細和深刻。今天看到一個有趣的JS題目,由此引發了自己對於這一塊知識的深入學習和梳理。

題目如下:

	setTimeout(function(){
		console.log(1);
	},0)
	
	new Promise(function(resolve) {
	    console.log(2);
	    resolve();
	}).then(function() {
	    console.log(3)
	})
	
	console.log(4);

問具體的輸出結果?正確的解答這道題,你必須明白JS中的兩個概念 -事件循環和宏任務、微任務。
我們先來看js中的事件循環,這裏盜用一張圖

在這裏插入圖片描述

導圖要表達的內容用文字來表述的話:

  • 同步和異步任務分別進入不同的執行"場所",同步的進入主線程,異步的進入Event Table並註冊函數。
  • 當指定的事情完成時,Event Table會將這個函數移入Event Queue。
  • 主線程內的任務執行完畢爲空,會去Event Queue讀取對應的函數,進入主線程執行。
  • 上述過程會不斷重複,也就是常說的Event Loop(事件循環)。

廣義的同步任務和異步任務,我們對任務有更精細的定義:

  • macro-task(宏任務):包括整體代碼script,setTimeout,setInterval
  • micro-task(微任務):Promise,process.nextTick

有了上面這些基礎知識,下面進行上面代碼的詳細

  1. 這段代碼作爲宏任務,進入主線程。
  2. 先遇到setTimeout,那麼將其回調函數註冊後分發到宏任務Event Queue。(註冊過程與上同,下文不再描述)
  3. 接下來遇到了Promise,new Promise立即執行,then函數分發到微任務Event Queue。
    遇到console.log(),立即執行。
  4. 好啦,整體代碼script作爲第一個宏任務執行結束,看看有哪些微任務?我們發現了then在微任務Event Queue裏面,執行。
  5. ok,第一輪事件循環結束了,我們開始第二輪循環,當然要從宏任務Event Queue開始。我們發現了宏任務Event Queue中setTimeout對應的回調函數,立即執行。
  6. 結束

這裏還有一個重要的知識點,那就是事件循環,宏任務,微任務的關係,如圖所示:

在這裏插入圖片描述

下面是我自己的總結。
JS是單線程的,它是通過事件循環機制來實現異步的。

首先是主線程執行當前棧中的任務,遇到同步任務繼續執行,遇到異步任務會將其放入Event Tables的事件隊列中。Event Tables的事件隊列又分爲兩類,一類是宏任務,一類是微任務。
當主線程的任務執行完畢後,回去任務隊列中取出任務來執行。此時會優先選取任務隊列中的爲任務,執行完微任務後,纔會去取宏任務執行。

對了,忘記說了,正確輸出是2,4,3,1。你做對了嗎?

本文參考自以下文章:

  1. 這一次,徹底弄懂 JavaScript 執行機制

  2. 併發模型與事件循環

  3. 理解 JavaScript 中的 macrotask 和 microtask

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章