深刻理解javascript編程中的同步和異步

JavaScript的優點之一是其如何處理異步代碼。異步代碼會被放入一個事件隊列,等到全部其餘代碼執行後才進行,而不會阻塞線程。然而,對於初學者來講,書寫異步代碼可能會比較困難。而在這篇文章裏,我將會消除你可能會有的任何困惑。
理解異步代碼javascript

JavaScript最基礎的異步函數是setTimeout和setInterval。setTimeout會在必定時間後執行給定的函數。它接受一個回調函數做爲第一參數和一個毫秒時間做爲第二參數。如下是用法舉例:html

console.log( "a" );
setTimeout(function() {
    console.log( "c" )
}, 500 );
setTimeout(function() {
    console.log( "d" )
}, 500 );
setTimeout(function() {
    console.log( "e" )
}, 500 );
console.log( "b" );

正如預期,控制檯先輸出「a」、「b」,大約500毫秒後,再看到「c」、「d」、「e」。我用「大約」是由於setTimeout事實上是不可預知的。實際上,甚至 HTML5規範都提到了這個問題:html5

「這個API不能保證計時會如期準確地運行。因爲CPU負載、其餘任務等所致使的延遲是能夠預料到的。」java


有趣的是,直到在同一程序段中全部其他的代碼執行結束後,超時纔會發生。因此若是設置了超時,同時執行了需長時間運行的函數,那麼在該函數執行完成以前,超時甚至都不會啓動。實際上,異步函數,如setTimeout和setInterval,被壓入了稱之爲Event Loop的隊列。node

Event Loop是一個回調函數隊列。當異步函數執行時,回調函數會被壓入這個隊列。JavaScript引擎直到異步函數執行完成後,纔會開始處理事件循環。這意味着JavaScript代碼不是多線程的,即便表現的行爲類似。事件循環是一個先進先出(FIFO)隊列,這說明回調是按照它們被加入隊列的順序執行的。JavaScript被 node選作爲開發語言,就是由於寫這樣的代碼多麼簡單啊。jquery

Ajaxweb

異步Javascript與XML(AJAX)永久性的改變了Javascript語言的情況。忽然間,瀏覽器再也不須要從新加載便可更新web頁面。 在不一樣的瀏覽器中實現Ajax的代碼可能漫長而且乏味;可是,幸好有jQuery(還有其餘庫)的幫助,咱們可以以很容易而且優雅的方式實現客戶端-服務器端通信。ajax

咱們可使用jQuery跨瀏覽器接口$.ajax很容易地檢索數據,然而卻不能呈現幕後發生了什麼。好比:編程

var data;
$.ajax({
    url: "some/url/1",
    success: function( data ) {
        // But, this will!
        console.log( data );
    }
})
// Oops, this won't work...
console.log( data );

較容易犯的錯誤,是在調用$.ajax以後立刻使用data,可是其實是這樣的:promise

xmlhttp.open( "GET", "some/ur/1", true );
xmlhttp.onreadystatechange = function( data ) {
    if ( xmlhttp.readyState === 4 ) {
        console.log( data );
    }
};
xmlhttp.send( null );

底層的XmlHttpRequest對象發起請求,設置回調函數用來處理XHR的readystatechnage事件。而後執行XHR的send方法。在XHR運行中,當其屬性readyState改變時readystatechange事件就會被觸發,只有在XHR從遠端服務器接收響應結束時回調函數纔會觸發執行。

處理異步代碼

異步編程很容易陷入咱們常說的「回調地獄」。由於事實上幾乎JS中的全部異步函數都用到了回調,連續執行幾個異步函數的結果就是層層嵌套的回調函數以及隨之而來的複雜代碼。

Node.js中的許多函數也是異步的。

JavaScript 使得編寫異步代碼很容易. 使用 promises, 事件, 或者命名函數來避免「callback hell」. 

相關文章
相關標籤/搜索