1. Node特性
Node的功能強大,它将JavaScript擴充到了更多領域,特别是後端網站伺服器開發。它是對高性能V8引擎的封裝,通過提供一系列優化的API類庫,使V8在浏覽器之外依然能高效運作。
Node的一大特性是對高性能的追求。首先,V8采用了編譯領域的一些最新技術,使代碼運作效率能夠接近C等底層語言。其次,Node利用了JavaScript的事件驅動特性來建構高度可擴充的伺服器程式,它采用事件循環架構,讓開發高效的伺服器程式變得簡單和安全。
Node提供了一系列非阻塞函數庫來支援事件循環特性。比如把檔案系統或資料庫操作封裝成事件驅動形式的函數接口,當對檔案系統發起請求時,程式不需要閑置等待硬碟把檔案讀取出來。
Node的強大特性還包括能在伺服器端運作JavaScript。除了可以用Node現有的庫來建構應用外,也可以輕松為其擴充新的庫。正因為Node容易擴充,在Node項目對外釋出後,其社群便迅速湧現出大量擴充庫。
2. 編寫程式
設計Node.js的一個主要目的是提供高度可擴充的伺服器環境,除了用V8引擎來解析JavaScript外,還提供了高度優化的應用庫,用來提高伺服器效率。比如HTTP子產品是專為快速非阻塞式HTTP伺服器而用C重新編寫的,例如:
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(9000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:9000');
這個示例首先通過require方法把HTTP庫包含到程式中,接着調用HTTP子產品的一個工廠方法來建立新的HTTP伺服器,并監聽在9000端口。
當調用createServer的時候,傳了一個匿名函數作為參數,此函數綁定在新建立伺服器的事件監聽器上進行request事件處理。每當一個新的通路請求到達Web伺服器,它都将調用指定的函數方法來處理,我們稱這類方法為回調。
例子中的回調函數有兩個參數,一個是請求的對象,一個是響應的對象。首先調用res.writeHead方法來設定HTTP響應頭,接着可以寫入HTTP正文及調用res.end方法關閉連接配接,但是因為調用end方法的同時還傳入了一個字元串,是以end方法将在把此内容發送給用戶端後才關閉。
例子的最後一行調用了console.log方法,它将在标準輸出stdout上列印資訊。
3. 事件循環
Node的一個核心功能就是事件循環,它采用的方式是,所有的I/O事件都應該是非阻塞的。這意味着需要讓程式暫停操作的HTTP請求、資料庫查詢、檔案讀寫,以及其他事情在資料傳回之前并不暫停執行。這些事件都将獨立運作,而後在資料準備好以後觸發一個事件。也就是說,用Node.js程式設計會用到很多回調函數。
比如Web伺服器被請求要從資料庫中讀取一些資料,然後傳回給使用者。首先,使用者的請求多是要Web伺服器傳回一個網頁,處理這個初始請求的回調函數A會先從請求的對象中确定要從資料庫讀取的内容,然後向資料庫發起請求,并傳入一個回調函數B供請求完成時使用。處理完請求後,回調函數A結束并傳回,當資料庫找到相應内容後,再觸發相應事件,事件循環隊列則調用回調函數B,讓它把資料發送給使用者。
4. 差錯處理
JavaScript包含了try/catch功能,但這個方法隻有當錯誤發生在内聯位置時才有用。比如使用Node的非阻塞I/O時,給函數傳遞了一個回調函數,當回調函數被事件觸發調用時,是不在try/catch代碼塊中的。是以我們需要為異步運作情景提供差錯處理的辦法,而error事件讓我們能夠處理所有使用的子產品中可能出現的問題,例如:
var http = require('http');
var opts = {
host: 'test.net',
port: 80,
path: '/'
};
var req = http.get(opts, function(res) {
console.log('This will nerver get called');
});
req.on('error', function(e)) {
console.log('Got that pesky error trapped');
});
5. 使用多處理器
Node提供了一個cluster子產品,可以把任務配置設定給子程序,每個子程序能夠與其他子程序共享socket連接配接。當使用cluster把工作共享到一組複制的Node程式時,主程序不會參與到每個具體的事務中,當子程序與I/O操作互動時,它們是直接進行操作的,不需要通過主程序。通過cluster API,可以把工作分布在伺服器所有可用的處理器上,例如:
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('death', function(worker) {
console.log('worker ' + worker.pid + ' died');
});
} else {
http.Server(function(req,res) {
res.writeHead(200);
res.end("Hello World\n");
}).listen(9000);
}