Nodejs學習筆記(二)
Node.js 回調函數
Node.js 異步編程的直接體現就是回調。
異步編程依托於回調來實現,但不能說使用了回調後程序就異步化了。
回調函數在完成任務後就會被調用,Node 使用了大量的回調函數,Node 所有 API 都支持回調函數。
例如,我們可以一邊讀取文件,一邊執行其他命令,在文件讀取完成後,我們將文件內容作為回調函數的參數返回。這樣在執行代碼時就沒有阻塞或等待文件 I/O 操作。這就大大提高了 Node.js 的性能,可以處理大量的並發請求。
阻塞代碼實例
創建一個文件 input.txt ,內容如下:
博客地址:http://www.cnblogs.com/gorgeous/
創建 main.js 文件, 代碼如下:
var fs = require("fs"); var data = fs.readFileSync(‘input.txt‘); console.log(data.toString()); console.log("程序執行結束!");
以上代碼執行結果如下:
$ node main.js
博客地址:http://www.cnblogs.com/gorgeous/
程序執行結束!
非阻塞代碼實例
創建一個文件 input.txt ,內容如下:
博客地址:http://www.cnblogs.com/gorgeous/
創建 main.js 文件, 代碼如下:
var fs = require("fs"); fs.readFile(‘input.txt‘, function (err, data) { if (err) return console.error(err); console.log(data.toString()); }); console.log("程序執行結束!");
以上代碼執行結果如下:
$ node main.js 程序執行結束!
博客地址:http://www.cnblogs.com/gorgeous/
以上兩個實例我們了解了阻塞與非阻塞調用的不同。第一個實例在文件讀取完後才執行完程序。 第二個實例我們不需要等待文件讀取完,這樣就可以在讀取文件時同時執行接下來的代碼,大大提高了程序的性能。
因此,阻塞是按順序執行的,而非阻塞是不需要按順序的,所以如果需要處理回調函數的參數,我們就需要寫在回調函數內。
如果有好幾層回調怎麽辦? 解決方案也有好幾種,常見到的是express上面的引用,以後我再寫
Node.js 事件循環
Node.js 是單進程單線程應用程序,但是通過事件和回調支持並發,所以性能非常高。
Node.js 的每一個 API 都是異步的,並作為一個獨立線程運行,使用異步函數調用,並處理並發。
Node.js 基本上所有的事件機制都是用設計模式中觀察者模式實現。
Node.js 單線程類似進入一個while(true)的事件循環,直到沒有事件觀察者退出,每個異步事件都生成一個事件觀察者,如果有事件發生就調用該回調函數.
事件驅動程序
Node.js 使用事件驅動模型,當web server接收到請求,就把它關閉然後進行處理,然後去服務下一個web請求。
當這個請求完成,它被放回處理隊列,當到達隊列開頭,這個結果被返回給用戶。
這個模型非常高效可擴展性非常強,因為webserver一直接受請求而不等待任何讀寫操作。(這也被稱之為非阻塞式IO或者事件驅動IO)
在事件驅動模型中,會生成一個主循環來監聽事件,當檢測到事件時觸發回調函數。
整個事件驅動的流程就是這麽實現的,非常簡潔。有點類似於觀察者模式,事件相當於一個主題(Subject),而所有註冊到這個事件上的處理函數相當於觀察者(Observer)。
Node.js 有多個內置的事件,我們可以通過引入 events 模塊,並通過實例化 EventEmitter 類來綁定和監聽事件,如下實例:
// 引入 events 模塊 var events = require(‘events‘); // 創建 eventEmitter 對象 var eventEmitter = new events.EventEmitter();
以下程序綁定事件處理程序:
// 綁定事件及事件的處理程序 eventEmitter.on(‘eventName‘, eventHandler);
我們可以通過程序觸發事件:
// 觸發事件 eventEmitter.emit(‘eventName‘);
實例
創建 main.js 文件,代碼如下所示:
// 引入 events 模塊 var events = require(‘events‘); // 創建 eventEmitter 對象 var eventEmitter = new events.EventEmitter(); // 創建事件處理程序 var connectHandler = function connected() { console.log(‘連接成功。‘); // 觸發 data_received 事件 eventEmitter.emit(‘data_received‘); } // 綁定 connection 事件處理程序 eventEmitter.on(‘connection‘, connectHandler); // 使用匿名函數綁定 data_received 事件 eventEmitter.on(‘data_received‘, function(){ console.log(‘數據接收成功。‘); }); // 觸發 connection 事件 eventEmitter.emit(‘connection‘); console.log("程序執行完畢。");
接下來讓我們執行以上代碼:
$ node main.js 連接成功。 數據接收成功。 程序執行完畢。
Node 應用程序是如何工作的?
在 Node 應用程序中,執行異步操作的函數將回調函數作為最後一個參數, 回調函數接收錯誤對象作為第一個參數。
接下來讓我們來重新看下前面的實例,創建一個 input.txt ,文件內容如下:
博客地址:http://www.cnblogs.com/gorgeous/
創建 main.js 文件,代碼如下:
var fs = require("fs"); fs.readFile(‘input.txt‘, function (err, data) { if (err){ console.log(err.stack); return; } console.log(data.toString()); }); console.log("程序執行完畢");
以上程序中 fs.readFile() 是異步函數用於讀取文件。 如果在讀取文件過程中發生錯誤,錯誤 err 對象就會輸出錯誤信息。
如果沒發生錯誤,readFile 跳過 err 對象的輸出,文件內容就通過回調函數輸出。
執行以上代碼,執行結果如下:
程序執行完畢
博客地址:http://www.cnblogs.com/gorgeous/
接下來我們刪除 input.txt 文件,執行結果如下所示:
程序執行完畢 Error: ENOENT, open ‘input.txt‘
因為文件 input.txt 不存在,所以輸出了錯誤信息。
Node.js REPL(交互式解釋器)---------->與回調無關,就是一個終端
-
讀取 - 讀取用戶輸入,解析輸入了Javascript 數據結構並存儲在內存中。
-
執行 - 執行輸入的數據結構
-
打印 - 輸出結果
-
循環 - 循環操作以上步驟直到用戶兩次按下 ctrl-c 按鈕退出。
Node 的交互式解釋器可以很好的調試 Javascript 代碼。
開始學習 REPL
我們可以輸入以下命令來啟動 Node 的終端:
$ node >
這時我們就可以在 > 後輸入簡單的表達式,並按下回車鍵來計算結果。
簡單的表達式運算
接下來讓我們在 Node.js REPL 的命令行窗口中執行簡單的數學運算:
$ node > 1 +4 5 > 5 / 2 2.5 > 3 * 6 18 > 4 - 1 3 > 1 + ( 2 * 3 ) - 4 3 >
使用變量
你可以將數據存儲在變量中,並在你需要的時候使用它。
變量聲明需要使用 var 關鍵字,如果沒有使用 var 關鍵字變量會直接打印出來。
使用 var 關鍵字的變量可以使用 console.log() 來輸出變量。
$ node > x = 10 10 > var y = 10 undefined > x + y 20 > console.log("Hello World") Hello World undefined > console.log("www.runoob.com") www.runoob.com undefined
多行表達式
Node REPL 支持輸入多行表達式,這就有點類似 JavaScript。接下來讓我們來執行一個 do-while 循環:
$ node > var x = 0 undefined > do { ... x++; ... console.log("x: " + x); ... } while ( x < 5 ); x: 1 x: 2 x: 3 x: 4 x: 5 undefined >
... 三個點的符號是系統自動生成的,你回車換行後即可。Node 會自動檢測是否為連續的表達式。
下劃線(_)變量
你可以使用下劃線(_)獲取表達式的運算結果:
$ node > var x = 10 undefined > var y = 20 undefined > x + y 30 > var sum = _ undefined > console.log(sum) 30 undefined >
REPL 命令
-
ctrl + c - 退出當前終端。
-
ctrl + c 按下兩次 - 退出 Node REPL。
-
ctrl + d - 退出 Node REPL.
-
向上/向下 鍵 - 查看輸入的歷史命令
-
tab 鍵 - 列出當前命令
-
.help - 列出使用命令
-
.break - 退出多行表達式
-
.clear - 退出多行表達式
-
.save filename - 保存當前的 Node REPL 會話到指定文件
-
.load filename - 載入當前 Node REPL 會話的文件內容。
停止 REPL
前面我們已經提到按下兩次 ctrl + c 鍵就能退出 REPL:
$ node > (^C again to quit) >
Nodejs學習筆記(二)