源文檔地址javascript
如何你跟我同樣的話,那麼你必定會愛上javascript!雖然它不是一種比較完美的編程語言,可是嚴格地說,還有其它比javascript更完美的語言來設計web嗎?因此請忽視javascript的缺陷吧。我喜歡web工做,而javascript使得我能夠用其來創建applications,從而跟web上的用戶聯繫起來!java
可是若是你深究javascript——你會發現,它的一些內部概念你須要花費許多時間才能真正理解!其中一個概念就是Event Loop,可能一個在web開發中工做了幾年的開發人員也沒有真正理解其含義和工做原理,無論怎樣,我但願經過這篇文章,能帶給你一些啓發:什麼是event loop?其實它並非那麼難以理解的!node
咱們一般所說的javascript,都是指瀏覽器端使用的javascript——由於咱們寫的javascript代碼大多數是用在客戶端的!無論怎樣,理解這些概念和技術是很是重要的:一、Javascript Engine(好比 Chrome's V8),二、Web API(如 DOM),三、Event Loop 和 Event Quene。git
你可能看過上面列舉的這些概念以後,你可能會這樣想:「好複雜呀!」,確實是這樣的!可是經過這篇文章待會兒你會發現,其實它們並無那麼複雜!github
在介紹event loop以前,咱們須要對javascript engine作一個簡單的理解來明白它是作什麼的!web
有幾種不一樣的js引擎,可是最流行的一個當屬谷歌的V8了(它並不只僅在瀏覽器環境中使用,經過nodejs,它也在服務器端使用)。可是js引擎的工做究竟是什麼呢?其實,引擎的工做很是簡單——它會遍歷咱們寫的全部js代碼,而後一個一個的執行它們。也就是說咱們的js是單線程的,單線程很差的地方就是,若是你同步執行了一段很長時間的代碼的話,那麼這段代碼後面的邏輯會被阻塞從而等待好久才能執行。同門一般都不想寫阻塞的代碼——特別是在瀏覽器中,設想若是你點擊了一個按鈕以後去執行了一個很長時間的阻塞代碼,這會致使你的頁面的其它交互效果會暫停,嚴重影響用戶體驗!編程
那麼js引擎是怎麼知道一個一個的處理代碼呢?其實它使用了call stack(調用棧)。你能夠把調用棧看做一個電梯——第一個進電梯的人最後一個出來,最後一個進電梯的人第一個出來!瀏覽器
咱們來看一個例子:服務器
/*Within main.js*/
var firstFunction = function(){
console.log("I'm first!");
};
var secondFunction = function(){
firstFunction();
console.log("I'm second!");
};
secondFunction();
/*Results: *=> I'm first! *=> I'm second! */複製代碼
首先,js引擎會維護一個調用棧序列的:app
到如今,咱們已經知道js引擎的調用棧的原理了,那麼咱們回到剛纔所討論的阻塞代碼的問題上,咱們都知道應該避免寫阻塞代碼!慶幸的是,js提供了一種機制來實現非阻塞:異步回調函數!咱們又接觸了一個概念,是否是覺得這個概念很牛逼呢?其實並非,異步回調函數跟你寫過的其它的普通的函數同樣的!只不過它不是同步執行的,若是你熟悉的setTimeout函數的話,它就是異步的,咱們來看一個例子:
/* Within main.js */
var firstFunction = function () {
console.log("I'm first!");
};
var secondFunction = function () {
setTimeout(firstFunction, 5000);
console.log("I'm second!");
};
secondFunction();
/* Results: * => I'm second! * (And 5 seconds later) * => I'm first! */複製代碼
咱們看一下調用棧序列是怎麼樣的!(爲了儘快說明問題,咱們快進了)
當調用棧在調用setTimeout的時候,發生了一塊兒特別的事情——瀏覽器會把setTimeout的回調函數放到(在這個例子中就是firstFunction)Event Table中。你能夠把Event Table理解成爲一個註冊機構,調用棧會告訴Event Table去註冊一個特別的函數,當特定的事件發生的時候去執行它,當特定的事件發生時,Event Table只是簡單的把這個函數移動到Event Quene裏面,Event Quene只是一個放置函數即將執行的暫存區,最後由Event Quene把函數移動到調用棧中。
你可能會問,Event Quene何時知道把回調函數放回到調用棧中呢?好,js引擎聽從一個簡單的規則:瀏覽器中存在一個進程會不斷地去檢查調用棧是否爲空,同時,不管任什麼時候候只要調用棧爲空,它會檢查Event Quene是否有待執行的函數隊列!若是調用棧爲空,那麼它會把Event Quene隊列裏面的第一個函數放到調用棧中,若是Event Quene爲空的話,那麼這個進程將會無限期地來回地進行檢查,好吧——咱們描述的這個就是所謂的Event Loop!