小結(jié)Node.js中非阻塞IO和事件循環(huán)
學(xué)習(xí)和使用Node.js已經(jīng)有兩個月,使用express結(jié)合mongoose寫了一個web應(yīng)用和一套RESTful web api,回過頭來看Node.js官網(wǎng)首頁對Node.js的介紹:Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.那么其中的non-blocking I/O model 意味著什么呢?
非阻塞的IO模型
首先,IO操作無疑是耗時的,當(dāng)服務(wù)器端接收到大量請求時,為每一個請求創(chuàng)建進(jìn)程或線程的同時,也增加了額外的內(nèi)存開銷,也可能浪費更多的時間資源。
由于Node.js是事件驅(qū)動的,于是它使用了事件循環(huán)來解決IO操作帶來的瓶頸問題。在Node.js中,一個IO操作通常會帶有一個回調(diào)函數(shù),當(dāng)IO操作完成并返回時,就會調(diào)用這個回調(diào)函數(shù),而主線程則繼續(xù)執(zhí)行接下來的代碼。簡單的用一個例子來說明這個問題:
request('http://www.google.com', function(error, response, body) {
console.log(body);
});
console.log('Done!');
這段代碼的意思是向'http://www.google.com'發(fā)出請求,當(dāng)請求返回這則調(diào)用回調(diào)函數(shù)輸出響應(yīng)信息。由于Node.js的運行機(jī)制,這段代碼運行后,會立即在控制臺輸出'Done!',然后一段時間后再輸出響應(yīng)的信息。
事件循環(huán) event loop
接下來,來討論下事件循環(huán)的機(jī)制。首先說說調(diào)用桟,比如有如下一段代碼:
function A(arg, func){
var a = arg;
func();
console.log('A');
}
function B(){
console.log('B');
}
A(0, B);
當(dāng)代碼執(zhí)行后,函數(shù)A首先被推入調(diào)用桟中成為棧頂元素并開始執(zhí)行A,在執(zhí)行過程中函數(shù)B又被推入調(diào)用桟成為棧頂元素,在B執(zhí)行完成后,B被彈出調(diào)用桟,A再次成為棧頂元素,在A執(zhí)行完成后A被彈出調(diào)用桟,調(diào)用桟呈空閑狀態(tài)。
在Javascript運行時中存在一個消息隊列,而消息和一個回調(diào)函數(shù)相關(guān)聯(lián),當(dāng)一個事件被觸發(fā)時,如果這個事件有相應(yīng)的回調(diào)函數(shù),則該消息就會被加入到消息隊列中去。
回過頭來說事件循環(huán)到底循環(huán)的是什么,在代碼開始執(zhí)行后,函數(shù)被不斷推入調(diào)用桟中,就拿上面的例子來講,request被推入調(diào)用桟中,這個函數(shù)將進(jìn)行一個http請求(這個http請求將交由Node.js的底層模塊來實現(xiàn))同時請求完成的事件和一個回調(diào)函數(shù)關(guān)聯(lián)起來,request被彈出調(diào)用桟,console.log被推入調(diào)用桟開始執(zhí)行。當(dāng)請求完成時,完成事件被觸發(fā),一條消息被添加進(jìn)消息隊列中,消息隊列首先會檢查調(diào)用桟是否為空閑狀態(tài),如果調(diào)用桟并不空閑,則會一直等待到調(diào)用桟空閑狀態(tài)后,將消息隊列的頭部彈出,此時與該消息相關(guān)聯(lián)的回調(diào)函數(shù)被執(zhí)行。
小結(jié)
以上就無阻塞模型和事件循環(huán)在概念上進(jìn)行了總結(jié)。而這個事件循環(huán)的機(jī)制并不僅僅是Node.js所獨有的,并且Node.js的代碼是單線程執(zhí)行的,在面對大量并發(fā)請求的時候,又有著什么優(yōu)勢呢?

上面這張圖展示了Node.js的架構(gòu)圖,Node.js的底層有一個模塊負(fù)責(zé)維護(hù)線程池,當(dāng)一個IO請求發(fā)出的時候,Node.js的底層模塊將新建一個線程來處理請求,完成后再將結(jié)果交還給上層。那么,當(dāng)有多個請求的時候,Node.js的底層模塊將利用盡可能少的線程來完成最多的任務(wù),如果存在空閑的線程,它將繼續(xù)被利用來做其他的事情,這對于前面說的針對每個請求開一個新的進(jìn)程或線程而言,無疑“聰明”許多,也更加高效了。
這篇文章是對學(xué)習(xí)Node.js的一個總結(jié),其中若有問題和不足,歡迎批評指正。
相關(guān)文章
Node.js中,在cmd界面,進(jìn)入退出Node.js運行環(huán)境的方法
今天小編就為大家分享一篇Node.js中,在cmd界面,進(jìn)入退出Node.js運行環(huán)境的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
使用Jasmine和Karma對AngularJS頁面程序進(jìn)行測試
這篇文章主要介紹了使用Jasmine和Karma對AngularJS頁面程序進(jìn)行測試的方法,以Node.js為環(huán)境,非常適合JavaScript的全棧開發(fā)時使用,需要的朋友可以參考下2016-03-03
Nodejs獲取網(wǎng)絡(luò)數(shù)據(jù)并生成Excel表格
這篇文章主要為大家詳細(xì)介紹了Nodejs獲取網(wǎng)絡(luò)數(shù)據(jù)并生成Excel表格的具體實現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-05-05
node使用mysql獲取數(shù)據(jù)庫數(shù)據(jù)中文亂碼問題的解決
這篇文章主要介紹了node使用mysql獲取數(shù)據(jù)庫數(shù)據(jù)中文亂碼問題的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
用npm install時報錯node-sass npm ERR command
在用npm install時報錯npm ERR! path D:…\node-sass和npm ERR! command failed 問題,本文給大家介紹了如何解決這個問題,文中通過圖文給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
React+react-dropzone+node.js實現(xiàn)圖片上傳的示例代碼
本篇文章主要介紹了React+react-dropzone+node.js實現(xiàn)圖片上傳的示例代碼,非常具有實用價值,需要的朋友可以參考下2017-08-08

