1. 程式人生 > >詳解JavaScript的執行機制:Event Loop(事件輪詢機制)

詳解JavaScript的執行機制:Event Loop(事件輪詢機制)

前言

有人稱Event Loop為事件迴圈機制,而我更願意將其解釋為事件輪詢機制,在之後的內容中你會感受到這一點的區別在哪裡。說是事件輪詢機制,我們也可以說是任務輪詢機制,因為英文是Event Loop,所以我們在此文中將其翻譯為事件輪詢。

閱讀本文之前,首先對JavaScript的單執行緒和非同步要有一定的瞭解,對此不瞭解的可以先閱讀一下我的另一篇博文《JavaScript的單執行緒和非同步》

ECMA只負責指定標準,Event Loop如何實現,它並不關心。
本文在概念的結構順序上參考了阮一峰老師的部落格《再談javascript的執行機制: Event Loop》,理解也大多源於此文,加上個人看法,以更容易讓讀者理解的方式表述出來。

在講JavaScript的事件輪詢機制之前,讓我們先來了解幾個重要的概念:

任務佇列

我們知道,由於JavaScript是單執行緒,這意味著所有任務都要排隊等待執行,後面的任務要等待前面的任務執行結束才能開始執行,如果前一個任務耗時比較久的話,後一個任務就必須一直等待。

我們在《JavaScript的單執行緒和非同步》一文中指出,CPU的運算能力往往是過剩的,我們等待的時間主要是IO操作的時間,這時候會發現,有時候javascript的主執行緒完全可以不管這些IO操作的任務,我們可以先將這些任務掛起,執行後面的任務,等到IO操作返回了結果,再將之前掛起的任務繼續執行。

根據上述的情況,我們大致可以將這分為兩種任務:同步任務(synchronous)

非同步任務(asynchronous)同步任務指主執行緒上排隊等待被執行的任務,這些任務在一個執行棧中,順序等待被執行,在主執行緒上的任務需要等待前一個任務執行結束才能被執行;非同步任務是指那些被主執行緒掛起的任務,非同步結果返回後一個事件被子執行緒放入“任務佇列”中等待被讀取進入主執行緒,而不是直接進入到主執行緒中等待被執行,這一點是要注意也是我們要著重強調的。而什麼時候才會執行任務佇列中的任務呢?我們先來看一張圖:
任務佇列流程圖
捋一下整個流程:
步驟1: 首先解析JavaScript程式碼,這時程式碼未執行,將同步任務放到執行棧中等待被執行;
步驟2: 對執行棧進行判斷,如果執行棧不為空則逐個執行排隊的任務(任務執行過程中產生的非同步任務拋給子執行緒進行處理,當任務結果返回時將一個事件放入任務佇列中等待被讀取);如果執行棧為空,則讀取任務佇列中可執行的事件,將其放到執行棧中等待被執行;
步驟3: 不斷重複步驟2的操作。

注:任務佇列也是一個先進先出的棧,先進入任務佇列的任務會先被讀取到執行棧中等待執行

注意:當執行棧空了,才會去讀取任務佇列,這個過程會不斷重複。 這就是JavaScript的執行機制,沒有我們想象的那麼什麼和複雜,對吧!

事件的概念

“任務佇列"是一個事件的佇列(也可以理解成訊息的佇列),非同步操作完成一項任務,就在"任務佇列"中新增一個事件,表示相關的非同步任務可以進入"執行棧"了。主執行緒讀取"任務佇列”,就是讀取裡面有哪些事件。
“任務佇列"中的事件,還包括滑鼠點選、鍵盤點選,定時操作等等。只要指定過回撥函式,這些事件發生時就會進入"任務佇列”,等待主執行緒讀取。

回撥函式

在講事件輪詢機制之前,我們還要了解一件事情,我們發起非同步任務的目的是什麼?是希望獲得需要的結果,然後根據這個結果去做一些事情對吧,如果非同步任務結果返回了,而我們什麼都不做的話,就失去了發起非同步任務的初衷!我們所謂的主執行緒掛起的任務,實際上是一段待執行程式碼,在非同步結果或者說是狀態返回時,我們執行這段程式碼,也就是執行非同步任務;而這裡的程式碼,我們稱之為回撥函式。

事件輪詢機制Event Loop:

終於講到在任務佇列一章中我們放了一張圖,主執行緒從"任務佇列"中讀取事件,這個過程是迴圈不斷的,故此,我們將其稱為Event Loop(直譯為事件迴圈),照例,先摔一張圖在這裡:
事件輪詢機制
上圖中,主執行緒執行的時候,產生堆(heap)棧(stack),棧中的程式碼呼叫各種外部API,它們在"任務佇列"中加入各種事件(click,load,error)。只要棧中的程式碼執行完畢,主執行緒就會去讀取"任務佇列",依次執行那些事件所對應的回撥函式。在這裡我們能夠更明確的看出任務佇列是一個先進先出的資料結構。

這就像是每次執行棧為空時,便會詢問任務佇列是否有可執行任務,這也是我文章開頭時為什麼將Event Loop解釋為事件輪詢機制。

注:本文沒有詳細區分“任務佇列“中的情況,之後會詳解“任務佇列”中的不同情況。

結語

此篇主要是講解了JavaScript的執行機制,後面我們會從程式碼層面來深入分析JavaScript在程式碼層面的體現。

希望此文能夠解決大家工作和學習中的一些疑問,避免不必要的時間浪費,有不嚴謹的地方,也請大家批評指正,共同進步!
轉載請註明出處,謝謝!

交流方式:QQ1670765991