JavaScript的優點之一是其如何處理異步代碼。異步代碼會被放入一個事件隊列,等到全部其餘代碼執行後才進行,而不會阻塞線程。然而,對於初學者來講,書寫異步代碼可能會比較困難。而在這篇文章裏,我將會消除你可能會有的任何困惑。javascript 理解異步代碼JavaScript最基礎的異步函數是setTimeout和setInterval。setTimeout會在必定時間後執行給定的函數。它接受一個回調函數做爲第一參數和一個毫秒時間做爲第二參數。如下是用法舉例:html
「這個API不能保證計時會如期準確地運行。因爲CPU負載、其餘任務等所致使的延遲是能夠預料到的。」 |
加壹
|
有趣的是,直到在同一程序段中全部其他的代碼執行結束後,超時纔會發生。因此若是設置了超時,同時執行了需長時間運行的函數,那麼在該函數執行完成以前,超時甚至都不會啓動。實際上,異步函數,如setTimeout和setInterval,被壓入了稱之爲
Event Loop的隊列。
Event Loop是一個回調函數隊列。當異步函數執行時,回調函數會被壓入這個隊列。JavaScript引擎直到異步函數執行完成後,纔會開始處理事件循環。這意味着JavaScript代碼不是多線程的,即便表現的行爲類似。事件循環是一個先進先出(FIFO)隊列,這說明回調是按照它們被加入隊列的順序執行的。JavaScript被 node選作爲開發語言,就是由於寫這樣的代碼多麼簡單啊。 |
加壹
|
Ajax異步Javascript與XML(AJAX)永久性的改變了Javascript語言的情況。忽然間,瀏覽器再也不須要從新加載便可更新web頁面。 在不一樣的瀏覽器中實現Ajax的代碼可能漫長而且乏味;可是,幸好有jQuery(還有其餘庫)的幫助,咱們可以以很容易而且優雅的方式實現客戶端-服務器端通信。github 咱們可使用jQuery跨瀏覽器接口$.ajax很容易地檢索數據,然而卻不能呈現幕後發生了什麼。好比:web
較容易犯的錯誤,是在調用$.ajax以後立刻使用data,可是其實是這樣的:ajax
底層的XmlHttpRequest對象發起請求,設置回調函數用來處理XHR的readystatechnage事件。而後執行XHR的send方法。在XHR運行中,當其屬性readyState改變時readystatechange事件就會被觸發,只有在XHR從遠端服務器接收響應結束時回調函數纔會觸發執行。編程 |
jinker
|
處理異步代碼異步編程很容易陷入咱們常說的「回調地獄」。由於事實上幾乎JS中的全部異步函數都用到了回調,連續執行幾個異步函數的結果就是層層嵌套的回調函數以及隨之而來的複雜代碼。 node.js中的許多函數也是異步的。所以以下的代碼基本上很常見:
下面的客戶端代碼也不少見:
Nested callbacks can get really nasty, but there are several solutions to this style of coding. 嵌套的回調很容易帶來代碼中的「壞味道」,不過你能夠用如下的幾種風格來嘗試解決這個問題
|
QiNark
|
命名函數清除嵌套回調的一個便捷的解決方案是簡單的避免雙層以上的嵌套。傳遞一個命名函數給做爲回調參數,而不是傳遞匿名函數:
此外, async.js 庫能夠幫助咱們處理多重Ajax requests/responses. 例如:
這段代碼執行兩個異步函數,每一個函數都接收一個名爲"done"的回調函數並在函數結束的時候調用它。當兩個"done"回調函數結束後,parallel函數的回調函數被調用並執行或處理這兩個異步函數產生的結果或錯誤。 |
ITgo
|
Promises模型引自 CommonJS/A:promise表示一個操做獨立完成後返回的最終結果。有不少庫都包含了promise模型,其中jQuery已經有了一個可以使用且很出色的promise API。jQuery在1.5版本引入了Deferred對象,並能夠在返回promise的函數中使用jQuery.Deferred的構造結果。而返回promise的函數則用於執行某種異步操做並解決完成後的延遲。
promise表示一個操做獨立完成後返回的最終結果。在這段代碼裏,geocode方法執行了兩次並返回了一個promise。異步函數以後執行,並在其回調裏調用了resolve。而後,一旦兩次調用resolve完成,then將會執行,其接收了以前兩次調用geocode的返回結果。結果以後被傳入getRoute,此方法也返回一個promise。最終,當getRoute的promise解決後,doSomethingCoolWithDirections回調就執行了。 |
加壹
|
事件事件是另外一種當異步回調完成處理後的通信方式。一個對象能夠成爲發射器並派發事件,而另外的對象則監聽這些事件。這種類型的事件處理方式稱之爲 觀察者模式 。 backbone.js 庫在withBackbone.Events中就建立了這樣的功能模塊。
事件循環是一個回調函數的隊列。一個相似的派發消息的方式稱爲 中介者模式 , postal.js 庫中用的便是這種方式。在中介者模式,有一個用於全部對象監聽和派發事件的中間人。在這種模式下,一個對象不與另外的對象產生直接聯繫,從而使得對象間都互相分離。 |
加壹
|
毫不要返回promise到一個公用的API。這不只關係到了API用戶對promises的使用,也使得重構更加困難。不過,內部用途的promises和外部接口的事件的結合,卻可讓應用更低耦合且便於測試。
在先前的例子裏面,doSomethingCoolWithDirections回調函數在兩個geocode函數完成後執行。而後,doSomethingCoolWithDirections纔會得到從getRoute接收到的響應,再將其做爲消息發送出去。
|
加壹
|
結論JavaScript 使得編寫異步代碼很容易. 使用 promises, 事件, 或者命名函數來避免「callback hell」. 爲獲取更多javascript異步編程信息,請點擊Async JavaScript: Build More Responsive Apps with Less . 更多的實例託管在github上,地址NetTutsAsyncJS,趕快Clone吧 ! |