簡單說說JavaScript的運行機制

主要是理解JavaScript的一些概念,比如單線程、任務隊列、同步任務、異步任務

一、什麼是單線程語言

   簡單的說就是,同一時間只能做同一件事。

二、任務隊列

   既然是單線程語言,那麼做的事情就要一件一件來。這就意味着所有的任務都需要排隊,前一個任務做完了,才能繼續下一個任務。

   所有的任務又分爲了兩種,一是同步任務,二是異步任務。

   同步任務指的是,在主線程上排隊執行的任務。

   異步任務指不進入主線程,而是進入任務隊列的任務。只有任務隊列通知主線程,某個任務可以執行了,該異步任務纔會進入主線程執行。

   由此可以知道,在JavaScript內部,分爲兩個任務序列,一個是主線程,放同步任務,裏面的同步任務按順序來執行。當全部執行完了之後,會通知任務隊列的異步任務,進入主線程執行。

舉個例子:

console.log(1);
setTimeout(function(){
   console.log(3)
},0)
console.log(2)

在瀏覽器中的打印結果是
1 2 3.
也就是說,setTimeout定時器是一個異步任務。只有當同步任務,也就是打印1 2執行完以後,纔會將定時器任務放到主線程上執行,打印3

  用更官方一點的話說,兩者的執行順序是這樣的:

(1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。
(2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
(3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,於是結束等待狀態,進入執行棧,開始執行。
(4)主線程不斷重複上面的第三步。

解釋一下第二步,什麼叫只要異步任務有了運行結果,就在任務隊列中放置一個事件。就拿定時器舉個例子,

比如定時器設置了1000ms之後執行,那麼只有到了這個規定的1000ms後,定時器的回調函數纔會進入任務隊列。然後等執行棧中的同步任務執行完之後,到任務隊列中去取異步任務。由此可以想得到,定時器規定的時間到後,其實並不一定會嚴格執行定時器中的回調函數,而是時間到後放入任務隊列。具體什麼時候執行回調函數,要看任務隊列的順序,和執行棧的同步任務執行情況。只是CPU處理任務很快,纔會感覺好像很準時。

三、關於事件和回調函數

     “任務隊列”是一個事件的隊列,IO設備完成一項任務,就在”任務隊列”中添加一個事件,表示相關的異步任務可以進入”執行棧”了。主線程讀取”任務隊列”,就是讀取裏面有哪些事件。

      “任務隊列”中的事件,除了IO設備的事件以外,還包括一些用戶產生的事件(比如鼠標點擊、頁面滾動等等)。只要指定過回調函數,這些事件發生時就會進入”任務隊列”,等待主線程讀取。

   就是說,比如給某個元素添加了一個點擊事件,那麼只有當點擊了這個元素的時候,相關事件纔會被放進任務隊列。其他的什麼mouseout、mouseover、滾動監聽,鍵盤事件啊都是這個道理。

      “任務隊列”是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,”任務隊列”上第一位的事件就自動進入主線程。

四、Event Loop

      主線程從”任務隊列”中讀取事件,這個過程是循環不斷的,所以整個的這種運行機制又稱爲Event Loop(事件循環)。

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