Event loop的化繁為簡(一)

GetFullStack發表於2018-03-23

最近在系統的學習Node.js,在學習過程中遇到了Event-loop這個東東,下面把我自己的一些心得進行總結,分享給大家。

Javascript真的是單執行緒執行嗎?

瞭解Javascript的同學應該知道Javascript是單執行緒執行的,比如在程式碼裡你打個alert,系統給你彈個框,後面的程式碼都給阻塞了,事實上也確實如此。因為如果系統給你new Thread的功能,二條執行緒同時更新一個dom,那不打架了麼~~~。

可是,單執行緒的執行模式是很不友好的,在很多場景下,都需要非同步來提高使用者體驗,於是老美那幫哥們就發明了Promise、Callback,setTimeoutt,setInterval,還有我們最常用的Ajax(XMLHttpRequest類) 等非同步程式設計介面,讓我們能開發出,更好使用者體驗的產品。

那麼問題又來了,如果在一個專案裡實用了這些非同步程式設計介面,他們是如何工作的,而且如何有效的控制他們的執行先後順序,這個我們必須要搞清楚,下面就來簡單分享一下。

在開始之前先談談【程式與執行緒】

為什麼要說程式與執行緒,我用最簡單通俗的話來講,大家開發用的瀏覽器Chrome,是一個多程式的瀏覽器;大家在開發時寫的setTimeout,setInterval, XMLHttpRequest類,是在一個程式裡開闢的新的執行緒。

好混亂。別急。畫圖。

chrome的一個切頁,對應一個程式

從上圖我們可以看到,一個Chrome切頁,就是一個網頁,也就是一個程式。同時在一個網頁裡,我們會寫很多程式碼,裡面有很多API呼叫,如Promise、Callback,setTimeoutt,setInterval,Ajax(XMLHttpRequest類),它們會開啟自己的一個執行緒去執行,網頁(程式)裡包含多個執行緒

  • 瀏覽器事件觸發執行緒(用來控制事件迴圈,存放setTimeout、瀏覽器事件、ajax的回撥函式)
  • 定時觸發器執行緒(setTimeout定時器所線上程)
  • 非同步HTTP請求執行緒(ajax請求執行緒)

瀏覽器的事件迴圈(Event-loop)

瀏覽器的事件迴圈
借用網上的圖片。工作原理總結如下:

  1. 所有同步任務都在棧記憶體圖中的(Stack框)的主執行緒上執行,形成一個執行棧,執行棧也表示作用域棧。
  2. 主執行緒之外,還存在一個任務佇列(callback quere框)。只要非同步任務(一個個執行緒)有了執行結果,就在任務佇列之中放置一個事件(回撥函式)。
  3. 一旦執行棧中的所有同步任務執行完畢,系統就會讀取任務佇列,將佇列中的事件(回撥函式)放到執行棧中依次執行
  4. 主執行緒從任務佇列中讀取事件,這個過程是迴圈不斷的。

瀏覽器的任務佇列執行方式

Node.js的事件迴圈(Event-loop)

Node.js的事件迴圈
借用網上的圖片。工作原理總結如下:

  1. 我們寫的node.js程式碼會交給v8引擎進行處理。
  2. 程式碼中可能會呼叫node.js Api(如:setTimeout, setInterval, setImmediate, I/O,process.nextTick,Promise等),node會交給libuv庫處理。
  3. libuv通過阻塞操作和多執行緒實現了非同步io,也就是說libuv內部是完全非同步的,這就是node.js的最大特點事件驅動的核心。
  4. 通過事件驅動的方式(Callback函式),將結果放到事件佇列中,最終交給我們的應用。

巨集任務和微任務

任務佇列可分為巨集任務和微任務

macro-task(巨集任務): script(全域性任務), setTimeout, setInterval, setImmediate, I/O, UI rendering。

micro-task(微任務): process.nextTick, 原生Promise(有些實現的promise將then方法放到了巨集任務中),Object.observe(已廢棄), MutationObserver

Javascript Event-loop的化繁為簡(二)

相關文章