Event Loop詳解

1.進程,單線程與多線
  • 進程: 運行的程序就是一個進程,好比你正在運行的瀏覽器,它會有一個進程。
  • 線程: 程序中獨立運行的代碼段。
  • 一個進程由單個或多個線程組成,線程是負責執行代碼的。
2.單線程與多線程的區別
  • 單線程 從頭執行到尾,一行一行執行,若是其中一行代碼報錯,那麼剩下代碼將再也不執行。同時容易代碼阻塞。
  • 多線程 代碼運行的環境不一樣,各線程獨立,互不影響,避免阻塞。
任務隊列

任務分兩種:node

一種是同步任務(synchronous),另外一種是異步任務(asynchronous)。ajax

  • 同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
  • 異步任務指的是,不進入主線程、而進入"任務隊列"(taskqueue)的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行

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

Js 中,有兩類任務隊列:宏任務隊列(macro tasks)和微任務隊列(micro tasks)。宏任務隊列能夠有多個,微任務隊列只有一個。那麼什麼任務,會分到哪一個隊列呢?瀏覽器

  • 宏任務:script(全局任務), setTimeout, setInterval, setImmediate, I/O, UI rendering.
  • 微任務:process.nextTick, Promise, Object.observer, MutationObserver.
    咱們上面講到,當stack空的時候,就會從任務隊列中,取任務來執行。共分3步:數據結構

  • 取一個宏任務來執行。執行完畢後,下一步。
  • 取一個微任務來執行,執行完畢後,再取一個微任務來執行。直到微任務隊列爲空,執行下一步。
  • 更新UI渲染。多線程

Event Loop 會無限循環執行上面3步,這就是Event Loop的主要控制邏輯。其中,第3步(更新UI渲染)會根據瀏覽器的邏輯,決定要不要立刻執行更新。畢竟更新UI成本大,因此,通常都會比較長的時間間隔,執行一次更新。異步

3. Event Loop(瀏覽器)

js既然是單線程,那麼確定是排隊執行代碼,那麼怎麼去排這個隊,就是Event Loop。雖然JS是單線程,但瀏覽器不是單線程。瀏覽器中分爲如下幾個線程:async

  • js線程
  • UI線程
  • 事件線程(onclick,onchange,...)
  • 定時器線程(setTimeout, setInterval)
  • 異步http線程(ajax)

其中JS線程和UI線程相互互斥,也就是說,當UI線程在渲染的時候,JS線程會掛起,等待UI線程完成,再執行JS線程.函數

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

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

在進程啓動時,node便會建立一個相似while(true)的循環,每執行一次循環體的過程咱們稱爲tick,每一個tick的過程就是查看是不是否有事件等待處理,若是有,就取出事件及其相關的回調函數。若是有關聯的回調函數,就執行他們,而後進入有下一個循環體

4.異步的事件

process.nextTick()
  • 性能上來講很輕量,時間複雜的O(1)
  • 回調函數保存在數組中,在一輪循環中數組中的回調函數所有執行完

    setImmediate()
  • 和上面同樣都是將回調函數延遲執行,不一樣上面的優先級別要高,緣由是事件循環對觀察者的檢查是有前後順序的,process.nextTick()屬於idle觀察者,setImmediat屬於check觀察者。在每一輪循環中,idle先與I/O觀察者,I/觀察者先於check觀察者。
  • 回調函數存在鏈表中,每一次循環只執行鏈表中的一個回調函數
    時間複雜度lg(n)

    定時器setTimeout()/setInterval()
  • 調用時會建立定時器會被插入到定時器觀察者內部的一個紅黑樹中,每次tick時,會取出定時器,檢查是否超時,若是超時,就造成一個事件,執行回調函數。問題就是時間不必定精確
  • 時間複雜度lg(n)

相關文章
相關標籤/搜索