(轉)理解javascript的同步與異步模式

你可能知道,Javascript語言的執行環境是”單線程”(single thread)。
所謂”單線程”,就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執行後面一個任務,以此類推。

這種模式的好處是實現起來比較簡單,執行環境相對單純;壞處是只要有一個任務耗時很長,後面的任務都必須排隊等着,會拖延整個程序的執行。常見的瀏覽器無響應(假死),往往就是因爲某一段Javascript代碼長時間運行(比如死循環),導致整個頁面卡在這個地方,其他任務無法執行。
爲了解決這個問題,Javascript語言將任務的執行模式分成兩種:同步(Synchronous)和異步(Asynchronous)。
“同步模式”就是上一段的模式,後一個任務等待前一個任務結束,然後再執行,程序的執行順序與任務的排列順序是一致的、同步的;”異步模式”則完全不同,每一個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,所以程序的執行順序與任務的排列順序是不一致的、異步的。
“異步模式”非常重要。在瀏覽器端,耗時很長的操作都應該異步執行,避免瀏覽器失去響應,最好的例子就是Ajax操作。在服務器端,”異步模式”甚至是唯一的模式,因爲執行環境是單線程的,如果允許同步執行所有http請求,服務器性能會急劇下降,很快就會失去響應。

異步調用並不會阻止代碼的順序執行,而是在將來的某一個時刻觸發設置好的邏輯,所以我們
並不知道邏輯什麼時候會被調用
只能定義當觸發的時候邏輯是什麼
只能等待,同時可以去處理其他的邏輯
setTimeout就是這樣的一個異步調用。
[javascript] view plain copy
var a = 1;
function f1(a){
console.log(“I am in f1”);
setTimeout(function () {
a += 2;
console.log(“f1:”+a);
}, 1000);
}
f1(a);
console.log(“out:”+a);
得到的結果如下所示:
I am in f1
out:1
f1:3
可以看出來代碼的執行過程確實是先執行了f1函數,再進行console輸出,但是setTimeout的回調函數卻在執行過程中被掛起,直到1s過後才被調用。在等待過程中javascript選擇先執行後面的操作,即console輸出。
實際上,異步函數,如setTimeout和setInterval,是被壓入了稱之爲Event Loop的隊列。

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

Node.js 使用事件驅動模型,當web server接收到請求,就把它關閉然後進行處理,然後去服務下一個web請求。當這個請求完成,它被放回處理隊列,當到達隊列開頭,這個結果被返回給用戶。這個模型非常高效可擴展性非常強,因爲webserver一直接受請求而不等待任何讀寫操作。(這也被稱之爲非阻塞式IO或者事件驅動IO)在事件驅動模型中,會生成一個主循環來監聽事件,當檢測到事件時觸發回調函數。

整個事件驅動的流程就是這麼實現的,非常簡潔。有點類似於觀察者模式,事件相當於一個主題(Subject),而所有註冊到這個事件上的處理函數相當於觀察者(Observer)。

在Node.js 異步編程的直接體現就是回調,下一篇將注重講解回調函數的使用。

轉自:http://blog.csdn.net/memeda_bupt/article/details/50961682

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章