javaScript中的任務隊列和事件循環

單線程的javaScript
JavaScript從一誕生就是單線程的,未來也不會改變。雖然HTML5提出Web Worker標準,允許JavaScript腳本創建多個線程,但是新標準並沒有改變JavaScript單線程的本質。

同步和異步
JavaScript中的任務可以分爲兩類:

  • 同步任務:在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務。
  • 異步任務:不進入主線程、而進入"任務隊列"(詳情看下文)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務纔會進入主線程執行。

一個異步過程包括兩個要素:註冊函數和回調函數,其中註冊函數用來發起異步過程,回調函數用來處理結果。

setTimeout(fn, time);

上面代碼中,setTimeout就是註冊函數,fn是回調函數。

一般而言,異步任務有以下三種類型:

  • 普通事件,如click
  • 資源加載,如load
  • 定時器,包括setIntervalsetTimeout等。

任務隊列
JavaScript 運行時,除了一個正在運行的主線程,引擎還提供一個“任務隊列”,裏面是各種需要當前程序處理的異步任務。

"任務隊列"是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,“任務隊列"上第一位的事件就自動進入主線程。但是,由於存在"定時器”,主線程首先要檢查一下執行時間,某些事件只有到了規定的時間,才能返回主線程。

事件循環
下圖中,主線程運行的時候,產生堆和棧,棧中的代碼調用各種外部API,異步操作執行完成後,就在任務隊列中排隊。只要棧中的代碼執行完畢,主線程就會去讀取任務隊列,依次執行那些異步任務所對應的回調函數。
在這裏插入圖片描述

詳細步驟如下:

  • 所有同步任務都在主線程上執行,形成一個執行棧。
  • 主線程之外,還存在一個"任務隊列"。只要異步操作執行完成,就到任務隊列中排隊。
  • 一旦執行棧中的所有同步任務執行完畢,系統就會按次序讀取任務隊列中的異步任務,於是被讀取的異步任務結束等待狀態,進入執行棧,開始執行。
  • 主線程不斷重複上面的第三步。

從代碼執行順序的角度來看,程序最開始是按代碼順序執行代碼的,遇到同步任務,立刻執行;遇到異步任務,則只是調用異步函數發起異步請求。此時,異步任務開始執行異步操作,執行完成後到任務隊列中排隊。程序按照代碼順序執行完畢後,查詢任務隊列中是否有等待的異步任務。如果有,則按照次序從任務隊列中取出放到執行棧中執行。執行完畢後,再從任務隊列中獲取異步任務,再執行,不斷重複。
由於主線程不斷的重複獲得、執行異步任務;又由於“任務隊列”是一個事件的隊列,主線程讀取“任務隊列”就是讀取裏面有哪些事件,所以,這種機制被稱爲事件循環。

寫在最後
本文參考文章如下:
JavaScript 運行機制詳解:再談Event Loop
深入理解javascript中的事件循環event-loop

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