1、瀏覽器端的事件驅動機制
javascript 在瀏覽器端運行是單線程的,這是由瀏覽器決定的,這是為了避免多線程執行不同任務會發生沖突的情況。也就是說我們寫的javascript 代碼只在一個線程上運行,稱之為主線程(HTML5提供了web worker API可以讓瀏覽器開一個線程運行比較復雜耗時的 javascript任務,但是這個線程仍受主線程的控制)。
有些操作比如說獲取遠程數據、I/O操作等,他們都很耗時,如果采用同步的方式,那么進程在執行這些操作時就會因為耗時而等待,就像上面那樣,下面的任務也只能等待,這樣效率並不高。
為了解決單線程帶來的阻塞問題很多操作系統實現了異步編程機制,瀏覽器中也是這么做的,主要表現如下:
(1)只在主線程中運行 javascript 代碼
(2)主線程一啟動就進入事件循環,整個過程就是不斷的循環,不斷地執行回調函數
(3)遇到網絡請求、I/O操作等時,瀏覽器會單開工作線程來處理,並設置相應的觀察者,然后立即返回主線程,主線程繼續執行下面的任務
(4)瀏覽器開的線程處理好任務或者有監聽的事件后會用得到的數據(或輸入)形成一個事件,放在相應觀察者的事件隊列中,事件隊列是在主線程中
(5)主線程不斷的循環,不斷檢查事件隊列,通過遍歷事件依次執行事件對應的回調函數
假設你發起了一個AJAX請求,無論你把這個請求寫在什么地方,它始終都在回調函數里。 因為事件驅動機制就是把一切抽象為事件,代碼開始執行也是一個事件,也會隱式調用回調函數,調用回調函數就是開始執行代碼。然后主線程發起異步任務后就會隨即返回,繼續執行"代碼開始事件"對應回調函數里的代碼,等到這個回調函數執行完畢,就會執行下一個事件。在這之間,Ajax線程會完成請求,然后把請求完成的事件(包含返回的數據)發送到事件隊尾中等待處理,等到主線程執行到這個事件時,指定的回調函數即被執行。
watcher機制 watcher,觀察者,是事件驅動系統重要的機制。
setTimeout稱為定時器,這是瀏覽器給的API。 每當你使用定時器,這個函數將會設置一個watcher,觀察者。主線程會不斷的循環,不斷的"經過"這里檢查時間,當主線程檢查時間間隔符合要求時,就會產生一個定時器事件,加入到這個watcher事件隊列中並執行回調函數。
因此執行setTimeout只是在時間到的時候產生了要調用回調函數的消息加入到了事件隊列中,因此,回調函數並不一定在指定的時間時調用,它取決於前面有多少等待處理的事件。
除此之外,還有I/O觀察者、網絡請求觀察者、鼠標事件觀察者、鍵盤事件觀察者等等等等,我們經常遇到事件監聽函數會讓你綁定一個回調函數,這種監聽函數一般就會設置watcher,其他線程產生的事件也會放到相應watcher的事件隊列中,因此每個watcher會產生自己的事件隊列。主線程在循環的時候,實際上是在依次調用這些watcher,檢查每個watcher的事件隊列,有事件就執行相應的回調。
它的過程就是 :進程一啟動就進入事件循環;有監聽就添加watcher;遍歷watcher下的事件隊列。
執行下一個watcher 事件驅動機制,它會有各種各樣的事件,大量的事件,它所做的一切都跟處理事件有關。但並不是所有的事件都有watcher,如果都有,主進程任務會變得非常繁重,況且有些事件我們並不關心,例如你只寫了一個定時器,代表你關心這個事件,那么點擊事件、網絡請求事件就不用關心,因為你根本就沒寫啊,也就沒有watcher。
2、在 node.js上的事件驅動機制
javascript 在 node.js上的事件驅動機制與瀏覽器端大致相同,都是單線程,都有event loop,上面講的javascript在瀏覽器端的事件循環機制在node上也是大致一樣的,不同的是執行者和執行者的行為不一樣,因為他們關注的任務不一樣:
node端異步機制和事件循環更加純粹一些。node為了支持高並發,所有的API幾乎都是異步的,這樣會充分利用操作系統的其他線程來幫忙完成任務,主線程只負責事件消費。例如當web server接收到請求,node就把它關閉,交給其他線程進行處理,然后去服務下一個web請求。當這個請求完成,它被放到處理隊列,當到達隊列開頭,這個結果被返回給用戶。這樣的話webserver一直接受請求而不等待任何讀寫操作,這種非阻塞型I/O性能很強。
瀏覽器端是瀏覽器負責執行BOM API,管理線程,處理用戶輸入信息等,在node上是node的一個核心庫libuv負責執行node API,管理主線程(運行javascript)和工作線程等。
解釋下“事件驅動”這個概念。所謂事件驅動,是指在持續事務管理過程中,進行決策的一種策略,即跟隨當前時間點上出現的事件,調動可用資源,執行相關任務,使不斷出現的問題得以解決,防止事務堆積。
Nodejs設計思想中以事件驅動為核心,事件驅動在於異步回調,他提供的大多數api都是基於事件的、異步的風格。而事件驅動的優勢在於充分利用系統資源,執行代碼無須阻塞等待某種操作完成,有限的資源用於其他任務。事件驅動機制是通過內部單線程高效率地維 護事件循環隊列來實現的,沒有多線程的資源占用和上下文的切換。
出處:https://www.jianshu.com/p/3115def9e1fe