[Node]基礎知識

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);
}

cluster工作的原理是每一個Node進程要麼是主進程,要麼成爲工作進程。當一個主進程調用cluster.fork()方法時,它會創建與主進程一樣的子進程。在主進程中,cluster.isMaster.isMaster返回true,而在子進程中,cluster.isWorker返回true。在使用cluster的地方使用listen()監聽一個socket的時候,多個進程可以同時監聽同一個socket。



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