Event Loop(事件輪詢)機制是一個常常把人搞暈的東東。我不敢說我徹底明白,只是在此談談個人淺見。數據庫
瀏覽器是一個事件驅動(event-driven)架構的軟件。它的UI線程中會不斷產生用戶事件。可是處理事件的JavaScript是單線程執行的,這是一個瀏覽器環境下難以改變的現狀(HTML5 Web Works沒有從本質上改變這個模型)。這意味着:在JavaScript處理某個任務(執行某段代碼)過程當中,若是產生了用戶事件,它不會當即被處理。那這種狀況該怎麼辦呢?瀏覽器
瀏覽器維護了一個「任務隊列」(一個優先隊列數據結構),它是一個瀏覽器進程資源。每當UI線程產生一個事件,事件對象就被當作任務放入任務隊列中(enqueue)。當JavaScript執行線程空閒的時候,隊列中的一個任務就會被送往JavaScript執行線程(dequeue),進行相應的處理。服務器
這個enqueue和dequeue的機制就是「Event Loop」。數據結構
可是,不只用戶事件能夠被Event Loop機制處理,還能更多的東西是依賴這個機制的。架構
<!--more-->異步
若是沒有異步的理念,這個世界會徹底不一樣:一個耗時的I/O操做(例如HTTP請求)會致使JavaScript執行線程等待,然後續的操做得不到執行。這種狀況下,一個耗時的服務器端數據庫操做http請求,會讓JavaScript執行線程阻塞,瀏覽器將長期處於假死狀態,在此期間,其餘後續操做(包括用戶的交互事件)得不到響應。函數
好在瀏覽器不是單線程的。它能夠(但不是必須)讓這些I/O任務讓其餘線程來託管,這樣就造成了一個執行任務的線程池。可是這些任務的結果總歸要回到JavaScript執行線程上處理,因而這些任務也被放到任務隊列中:須要被託管的任務被放入隊列中(enqueue),已完成的任務會被從隊列中一個個取出(dequeue),回到JavaScript執行線程執行回調。在這些耗時的I/O任務被託管的時候,JavaScript執行線程能夠執行其餘代碼。oop
在Node中,這個過程是相似的。本文不表。學習
這即是異步的原理了。咱們看到它一樣依賴Event Loop的機制。線程
瀏覽器的全局對象window提供了兩個方法,setTimeout和setInterval。這兩個方法實際上是調用了瀏覽器的API,將一個任務移除出JavaScript執行線程中,延時處理。
咱們如今立刻能夠反應過來:這個將要被延時的任務一樣是放到了任務隊列中。在一次Event Loop過程當中,它會優先將該時間點下已經到時的延時任務移除出隊列,放入JavaScript執行線程中。這意味着,任務隊列是一個優先隊列。
可是因爲JavaScript執行線程的執行時間是不肯定的,因此這個延時只是一個大致的值,它取決於JavaScript執行線程的執行時間。
任務完成的時候,JavaScript須要執行哪段代碼來處理呢?固然是回調函數了。
可是難免奇怪的一點就是:JavaScript中怎麼知道要執行的是哪一個回調函數呢?答案就是:任務被放入任務隊列的時候,該任務的回調函數會被註冊(註冊到什麼地方?須要進一步探究)。這樣,當特定任務完成的時候,任務結果和回調標記會返回給JavaScript執行線程,進入執行棧。
與其餘任務不一樣,事件並非由JavaScript執行線程發出的,而是從UI線程中發出的。
事件處理器和回調函數相似。可是特定的事件處理器在瀏覽器進入異步事件驅動階段時就會針對特定的事件註冊。當事件對象返回到JavaScript執行線程時,事件處理器也會同時進入執行棧中執行。
越日後寫,愈加現我以前的一些理解有誤差。在學習過程當中,我也要多反思,多總結。以前寫的不對的地方,我也會盡早糾正。