Node讀書筆記

魯鵬發表於2016-02-03

學習Node的書單早早就列了出來,接下來就是一步一步的進行學習。

  • 《Node.js開發指南》
  • 《Node與Express開發》
  • 《Node.js實戰》
  • 《深入淺出Node.js》
  • 《Node.js+MongoDB+AngularJS Web開發》

    《Node.js開發指南》學習筆記一

1. 除錯Node

supervisor

如果你有PHP 開發經驗,會習慣在修改PHP 指令碼後直接重新整理瀏覽器以觀察結果,而你在開發Node.js 實現的HTTP 應用時會發現,無論你修改了程式碼的哪一部份,都必須終止Node.js 再重新執行才會奏效。這是因為Node.js 只有在第一次引用到某部份時才會去解析指令碼檔案,以後都會直接訪問記憶體,避免重複載入,而PHP 則總是重新讀取並解析指令碼(如果沒有專門的優化配置)。Node.js的這種設計雖然有利於提高效能,卻不利於開發除錯,因為我們在開發過程中總是希望修改後立即看到效果,而不是每次都要終止程式並重啟。

安裝supervisor,使用npm模組管理器,npm install -g supervisor,然後,使用supervisor app.js來啟動app.js,當程式碼被改動的時候,指令碼自動重啟。

2. Node非同步程式設計

  • 同步式I/O(Synchronous I/O)就是阻塞式I/O(Blocking I/O)
  • 非同步式I/O(Asynchronous I/O)就是非阻塞式I/O(Non-blocking I/O)

阻塞模式下,一個執行緒只能處理一項任務,要想提高吞吐量必須通過多執行緒。而非阻塞模式下,一個執行緒永遠在執行計算操作,這個執行緒所使用的CPU 核心利用率永遠是100%,I/O 以事件的方式通知。在阻塞模式,多執行緒往往能提高系統吞吐量,因為一個執行緒阻塞時還有其他執行緒在工作,多執行緒可以讓CPU 資源不被阻塞中的執行緒浪費。而在非阻塞模式下,執行緒不會被I/O 阻塞,永遠在利用CPU。多執行緒帶來的好處僅僅是在多核CPU 的情況下利用更多的核,而Node.js的單執行緒也能帶來同樣的好處。這就是為什麼Node.js 使用了單執行緒、非阻塞的事件程式設計模式.

同步方式讀取檔案

var fs = require('fs');
var data = fs.readFileSync('file.txt' , 'utf-8');
console.log(data);
console.log('end.\n');

非同步方式讀取檔案

var fs = require('fs');
fs.readFile('file.txt' , 'utf-8' , function(err,data){
    if(err){
        console.log(err);
    }else{
        console.log(data);
    }
});
console.log('end.\n');

3. 模組與包

Node.js中模組和包沒有本質的區別,都是一個檔案。兩個概念時常混用。一個檔案可以是一個模組,一個模組也可以寫在一個檔案中。

3.1 模組

  • Node的模組是單次載入,比如下面的例子。

    //modele.js
    var Name;
    exports.setName = function(name){
        Name = name;
    }
    exports.sayHello = function(){
        console.log("Hello " + Name);
    }
    
    
    //single.js
    var hello1 = require('./module');
    hello1.setName('zhangsan');
    var hello2 = requier('./module');
    hello2.setName('lisi');
    
    
    hello1.sayHello();
    

    你會發現結果會是Hello lisi,因為hello1,hello2是同一個例項的不同引用而已。

  • 匯出物件的函式 exports.hello = hello

  • 匯出物件 module.exports = hello

3.2 包

包通常是一些模組的集合,在模組的基礎上提供了更高層的抽象,相當於提供了一些固定介面的函式庫。

包的安裝分為全域性模式以及本地模式,本地安裝只是將包安裝在了當前目錄的node_modules子目錄下;而全域性模式安裝的時候會將包安裝在了系統目錄下,比如/usr/local/lib/node_modules/,不一定是這個目錄,這取決於你的系統以及node的安裝目錄。

大部分情況下使用全域性模式安裝的包會自動定義到PATH環境變數中,也就是可以直接通過命令列還執行。然而使用全域性模式安裝的包卻不能在Javascript檔案中使用require獲取到。

總而言之,當我們要把某個包作為工程執行時的一部分時,通過本地模式獲取,如果要在命令列下使用,則使用全域性模式安裝。

《Node.js開發指南》學習筆記二

HTTP模組可是說是Node裡面最基礎最核心的模組。也是Node區別於其他語言的一個特點,使用Node搭建網站無需再配置Http伺服器,HTTP模組就提供了服務。

通過HTTP模板可以輕鬆搭建HTTP伺服器以及客戶端,下面記錄了一些重要的概念。

1. HTTP伺服器

瞭解過Node基本上就能寫出下面的Hello,World程式碼。

var http = require('http');
http.createServer(function (req,res){
  res.writeHead(200 , {"Content-Type" : "text/html"});
  res.end("hello,world!");
}).listen(8888);
console.log("Your server is started @ http://localhost:8888");

上面這段程式碼是學習Node最開始都要接觸的所謂的Hello,World!。下面的筆記或許能幫助做進一步瞭解。

  1. http.server 伺服器物件,繼承至EventEmitter。

    • createServer()函式返回一個http.server物件
    • 請求到來時,request事件被觸發
    • req以及res兩個引數分別是http.ServerRequesthttp.ServerResponse物件的例項
    • TCP連線建立,connection事件被觸發,提供scoket引數為net.Socket例項
    • 伺服器關閉時,close事件被觸發。

    根據上面的筆記,可以進一步瞭解HTTP伺服器建立的細節,那麼上面的那段程式碼就可以寫成下面這個樣子。

    var http = require('http');
    var server = new http.Server();
    server.on('request',function(req,res){
      res.writeHead(200,{"content-Type" : "text/html"});
      res.end("Hello,World!");
    });
    server.listen(3000);
    console.log("Server is started @ http://localhost:3000");    
    

    顯式寫出http伺服器的程式碼,證明對於Node的事件驅動的瞭解又深入了一步。

  2. http.ServerRequest HTTP請求資訊物件

    • HTTP請求:請求頭(Request Header)和請求體(Request Body)
    • 當請求體資料到來時,觸發data事件,事件提供chunk引數,表示接受到的資料
    • 資料傳輸完成,觸發end事件
    • 使用者請求結束,觸發close事件
  3. http.ServerResponse 伺服器響應物件

    • 返回客戶端的資訊,決定使用者最終看到的結果。
    • 返回響應頭,響應內容以及結束內容
      • response.writeHead(statusCodes, [Headers])
      • response.write()
      • response.end()

2. HTTP客戶端

在Node中通過HTTP模組也可以實現客戶端的功能,主要通過兩個函式http.requesthttp.get作為客戶端向HTTP伺服器傳送請求。

  1. http.request(options, callback) 傳送請求 請求引數:options,包括host、post、method、path、headers 請求內容:contents,

  2. http.get(options, callback) 傳送Get請求,該方法是上面的簡化版。

  3. http.clientRequest 客戶端請求物件 由http.requesthttp.get返回產生的物件,表示一個已經產生而且正在進行中得HTTP請求。如:var req = http.get()http.ClientRequesthttp.ServerResponse一樣也提供了writeend函式,用於向伺服器傳送請求體,通常用於POSTPUT等操作。

  4. http.clientResponse 客戶端響應物件 與http.ServerRequest相似,都有3個事件dataendclose,分別在資料到達,資料結束,斷開連線時觸發事件。http.clientResponse還提供了幾個特殊的函式。

    • res.setEncoding([encoding]):設定預設的編碼,當data事件被觸發時,資料將會以encoding編碼。
    • res.pause():暫停接收資料和傳送事件,方便實現下載功能。
    • res.resume():從暫停的狀態中恢復

看下下面這個例子,HTTP客戶端向伺服器發起Get請求。

var http = require('http');
var options = {
  host: "127.0.0.1",
  port: 3000,
  path: "/index.html?name=lupeng"
}
var req = http.get(options,function(res){
  res.setEncoding('utf8');
  var content = '';
  res.on('data',function(data){
    console.log(data);
  });
});