筆記來自《Node.js開發指南》BYVoid編著
第4章 Node.js核心模組
4.1、全域對象
Node.js中的全域對象是global,所有全域變數(除了global本身以外)都是global對象的屬性。我們在Node.js中能夠直接存取到對象通常都是global的屬性,如console、process等。
永遠使用var定義變數以避免引入全域變數,因為全域變數會汙染命名空間,提高代碼的耦合風險。
process用於描述當前Node.js進程狀態的對象,提供了一個與作業系統的簡單介面。
process.argv是命令列參數數組,第一個元素是node,第二個元素是指令檔名,從第三個元素開始每個元素是一個運行參數。
process.stdout是標準輸出資料流,通常我們使用的console.log()向標準輸出列印字元,而process.stdout.write()函數提供了更底層的介面。
process.stdin是標準輸入資料流,初始時它是被暫停,要想從標準輸入讀取資料,你必須恢複流,並手動編寫流的事件響應函數。
process.nextTick(callback)的功能是為事件迴圈設定一項任務,Node.js會在下次事件迴圈調響應時調用callback。
一個Node.js進程只有一個線程,因此在任何時刻都只有一個事件在執行。如果這個事件佔用大量的CPU時間,執行事件迴圈中的下一個事件就需要等待很久,因此Node.js的一個編程原則就是盡量縮短每個事件的執行時間。process.nextTick()提供了一個這樣的工具,可以把複雜的工作拆散,變成一個個較小的事件。供了一個這樣的工具,可以把複雜的工作
process還展示了process.platform、process.pid、process.execPath、process.memoryUsage()等方法,以及POSIX進程訊號響應機制。有興趣的讀者可以訪問http://nodejs.org/api/process.html瞭解詳細內容。
console用於向標準輸出資料流(stdout)或標準錯誤流(stderr)輸出字元。
console.log():向標準輸出資料流列印字元並以分行符號結束。如果有多個參數,則以類似於C語言printf()命令的格式輸出。第一個參數是一個字串,如果沒有參數,只列印一個換行。
console.error():與console.log()用法相同,只是向標準錯誤流輸出。
console.trace():向標準錯誤流輸出當前的調用棧。
4.2、常用工具util
util是一個Node.js核心模組,提供常用函數的集合,用於彌補核心JavaScript的功能過於精簡的不足。
util.inherits(constructor,superConstructor)是一個實現對象間原型繼承的函數。
var util = require('util');function Base() {this.name = 'base';this.base = 1989;this.sayHello = function() {console.log('Hello ' + this.name);};}Base.prototype.showName = function() {console.log(this.name);};function Sub() {this.name = 'sub';}util.inherits(Sub, Base);var objBase = new Base();objBase.showName();objBase.sayHello();console.log(objBase);var objSub = new Sub();objSub.showName();//objSub.sayHello();console.log(objSub);/*運行結果:baseHello base{ name: 'base', base: 1991, sayHello: [Function] }sub{ name: 'sub' } */
Sub僅僅繼承了Base在原型中定義的函數,而建構函式內部創造的base屬性和sayHello函數都沒有被Sub繼承。同時,在原型中定義的屬性不會被console.log作為對象的屬性輸出。
util.inspect(object,[showHidden],[depth],[colors])是一個將任意對象轉換為字串的方法,通常用於調試和錯誤輸出。它至少接受一個參數object,即要轉換的對象。
showHidden是一個選擇性參數,如果值為true,將會輸出更多隱藏資訊。
depth表示最大遞迴的層數,如果對象很複雜,你可以指定層數以控制輸出資訊的多少。如果不指定depth,預設會遞迴2層,指定為null表示將不限遞迴層數完整遍曆對象。
如果color值為true,輸出格式將會以ANSI顏色編碼,通常用於在終端顯示更漂亮的效果。
特別要指出的是,util.inspect並不會簡單地直接把對象轉換為字串,即使該對象定義了toString方法也不會調用。
var util = require('util');function Person() {this.name = 'ichenxiaodao';this.toString = function() {return this.name;};}var obj = new Person();console.log(util.inspect(obj));console.log(util.inspect(obj, true));/*運行結果:{ name: 'ichenxiaodao', toString: [Function] }{ name: 'ichenxiaodao', toString: { [Function] [length]: 0, [name]: '', [arguments]: null, [caller]: null, [prototype]: { [constructor]: [Circular] } } } */
除了以上我們介紹的幾個函數之外,util還提供了util.isArray()、util.isRegExp()、util.isDate()、util.isError()四個類型測試載入器,以及util.format()、util.debug()等工具。有興趣的讀者可以訪問http://nodejs.org/api/util.html瞭解詳細內容。
4.3、事件驅動events
events是Node.js最重要的模組,沒有“之一”,原因是Node.js本身架構就是事件式的,而它提供了唯一的介面,所以堪稱Node.js事件編程的基石。events模組不僅用於使用者代碼與Node.js下層事件迴圈的互動,還幾乎被所有的模組依賴。
events模組只提供了一個對象:events.EventEmitter。EventEmitter的核心就是事件發射與事件監聽器功能的封裝。EventEmitter的每個事件由一個事件名和若干個參數組成,事件名是一個字串,通常表達一定的語義。對於每個事件,EventEmitter支援若干個事件監聽器。當事件發射時,註冊到這個事件的事件監聽器被依次調用,事件參數作為回呼函數參數傳遞。
var events = require('events');var emitter = new events.EventEmitter();//註冊事件//指定事件註冊一個監聽器,接受一個字串event和一個回呼函數listener。emitter.on("someEvent", function(arg1, arg2) {console.log("listener1", arg1, arg2);});//註冊事件emitter.on("someEvent", function(arg1, arg2) {console.log("listener2", arg1, arg2);});//發射事件//發射event事件,傳遞若干選擇性參數到事件監聽器的參數表。emitter.emit("someEvent", "ichenxiaodao", 1989);/*運行結果:listener1 ichenxiaodao 1989listener2 ichenxiaodao 1989 */EventEmitter.once(event,listener)為指定事件註冊一個單次監聽器,即監聽器最多隻會觸發一次,觸發後立刻解除該監聽器。
EventEmitter.removeListener(event,listener)移除指定事件的某個監聽器,listener必須是該事件已經註冊過的監聽器。
EventEmitter.removeAllListeners([event])移除所有事件的所有監聽器,如果指定event,則移除指定事件的所有監聽器。
更詳細的API文檔參見http://nodejs.org/api/events.html。
EventEmitter定義了一個特殊的事件error,它包含了“錯誤”的語義,我們在遇到異常的時候通常會發射error事件。當error被發射時,EventEmitter規定如果沒有響應的監聽器,Node.js會把它當作異常,退出程式並列印調用棧。我們一般要為會發射error事件的對象設定監聽器,避免遇到錯誤後整個程式崩潰。
var events = require('events');var emitter = new events.EventEmitter();emitter.emit('error');/*運行結果:events.js:74 throw TypeError('Uncaught, unspecified "error" event.'); ^TypeError: Uncaught, unspecified "error" event. at TypeError (<anonymous>) at EventEmitter.emit (events.js:74:15) at Object.<anonymous> (/Users/cdz/workspace/my-node/NodeJS_Dev_Guide_Book/4/error.js:5:9) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:906:3 */大多數時候我們不會直接使用EventEmitter,而是在對象中繼承它。包括fs、net、http在內的,只要是支援事件響應的核心模組都是EventEmitter的子類。
原因是:首先,具有某個實體功能的對象實現事件符合語義,事件的監聽和發射應該是一個對象的方法。其次JavaScript的對象機制是基於原型的,支援部分多重繼承,繼承EventEmitter不會打亂對象原有的繼承關係。
4.4、檔案系統fs
fs模組是檔案操作的封裝,它提供了檔案的讀取、寫入、更名、刪除、遍曆目錄、連結等POSIX檔案系統操作。與其他模組不同的是,fs模組中所有的操作都提供了非同步和同步的兩個版本,例如讀取檔案內容的函數有非同步fs.readFile()和同步的fs.readFileSync()。
fs.readFile(filename,[encoding],[callback(err,data)])是最簡單的讀取檔案的函數。它接受一個必選參數filename,表示要讀取的檔案名稱。第二個參數encoding是可選的,表示檔案的字元編碼。callback是回呼函數,用於接收檔案的內容。如果不指定encoding,則callback就是第二個參數。回呼函數提供兩個參數err和data,err表示有沒有錯誤發生,data是檔案內容。如果指定了encoding,data是一個解析後的字串,否則data將會是以Buffer形式表示的位元據。
Node.js的非同步編程介面習慣是以函數的最後一個參數為回呼函數,通常一個函數只有一個回呼函數。回呼函數是實際參數中第一個是err,其餘的參數是其他返回的內容。如果沒有發生錯誤,err的值會是null或undefined。如果有錯誤發生,err通常是Error對象的執行個體。
fs.readFileSync(filename,[encoding])是fs.readFile同步的版本。它接受的參數和fs.readFile相同,而讀取到的檔案內容會以函數返回值的形式返回。如果有錯誤發生,fs將會拋出異常,你需要使用try和catch捕捉並處理異常。
fs.open(path,flags,[mode],[callback(err,fd)])
fs.read(fd,buffer,offset,length,position,[callback(err,bytesRead,buffer)])
4.5、HTTP伺服器與用戶端
Node.js標準庫提供了http模組,其中封裝了一個高效的HTTP伺服器和一個簡易的HTTP用戶端。http.Server是一個基於事件的HTTP伺服器,它的核心由Node.js下層C++部分實現,而介面由JavaScript封裝,兼顧了高效能與簡易性。http.request則是一個HTTP用戶端工具,用於向HTTP伺服器發起請求。
var http = require('http');http.createServer(function(req, res) {res.writeHead(200, {'Content-Type': 'text/html'});res.write('<h1>Node.js</h1>');res.end('<p>Hello World</p>');}).listen(3000);console.log("HTTP server is listening at port 3000.");http.createServer建立了一個http.Server的執行個體,將一個函數作為HTTP請求處理函數。這個函數接受兩個參數,分別是請求對象(req)和響應對象(res)。
http.Server是一個基於事件的HTTP伺服器,所有的請求都被封裝為獨立的事件,開發人員只需要對它的事件編寫響應函數即可實現HTTP伺服器的所有功能。它繼承自EventEmitter
前面例子顯式的實現方法:
var http = require('http');var server = new http.Server();server.on('request', function(req, res) {res.writeHead(200, {'Content-Type': 'text/html'});res.write('<h1>Node.js</h1>');res.end('<p>Hello World</p>');});server.listen(3000);console.log("HTTP server is listening at port 3000.");http.ServerRequest是HTTP請求的資訊,是後端開發人員最關注的內容。它一般由
http.Server的request事件發送,作為第一個參數傳遞,通常簡稱request或req。
由於GET請求直接被嵌入在路徑中,URL是完整的請求路徑,包括了?後面的部分,因此你可以手動解析後面的內容作為GET請求的參數。Node.js的url模組中的parse函數提供了這個功能。
var http = require('http');var url = require('url');var util = require('util');http.createServer(function(req, res) {res.writeHead(200, {'Content-Type': 'text/plain'});res.end(util.inspect(url.parse(req.url, true)));}).listen(3000);/*訪問:http://127.0.0.1:3000/user?name=ichenxiaodao&email=ichenxiaodao@gmail.com返回:{ protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: '?name=ichenxiaodao&email=ichenxiaodao@gmail.com', query: { name: 'ichenxiaodao', email: 'ichenxiaodao@gmail.com' }, pathname: '/user', path: '/user?name=ichenxiaodao&email=ichenxiaodao@gmail.com', href: '/user?name=ichenxiaodao&email=ichenxiaodao@gmail.com' }*/手動解析POST請求體。
var http = require('http');var querystring = require('querystring');var util = require('util');http.createServer(function(req, res) {var post = '';req.on('data', function(chunk) {post += chunk;});req.on('end', function(chunk) {post = querystring.parse(post);res.end(util.inspect(post));});}).listen(3000);http.ServerResponse是返回給用戶端的資訊,決定了使用者最終能看到的結果。它也是由http.Server的request事件發送的,作為第二個參數傳遞,一般簡稱為response或res。
http.ServerResponse有三個重要的成員函數:
response.writeHead(statusCode,[headers])
response.write(data,[encoding])
response.end([data],[encoding])
http模組提供了兩個函數http.request和http.get,功能是作為用戶端向HTTP伺服器發起請求。
var http = require('http');var querystring = require('querystring');var contents = querystring.stringify({name: "ichenxiaodao",email: "ichenxiaodao@gmail.com",address: "Shanghai"});var options = {host: "www.byvoid.com",path: "/application/node/post.php",method: "POST",headers: {"Content-Type": "application/x-www-form-urlencoded","Content-Length": contents.length}};var req = http.request(options, function(res) {res.setEncoding('utf-8');res.on('data', function(data) {console.log(data);});});req.write(contents);req.end();http.get(options,callback)http模組還提供了一個更加簡便的方法用於處理GET請求:http.get。它是http.request的簡化版,唯一的區別在於http.get自動將要求方法設為了GET請求,同時不需要手動調用req.end()。
http.ClientRequest是由http.request或http.get返回產生的對象,表示一個已經產生而且進行中中的HTTP請求。它提供一個response事件,即http.request或http.get第二個參數指定的回呼函數的綁定對象。
http.ClientRequest像http.ServerResponse一樣也提供了write和end函數,用於向伺服器發送請求體,通常用於POST、PUT等操作。所有寫結束以後必須調用end函數以通知伺服器,否則請求無效。
http.ClientResponse與http.ServerRequest相似,提供了三個事件data、end
和close,分別在資料到達、傳輸結束和串連結束時觸發,其中data事件傳遞一個參數chunk,表示接收到的資料。
拓展閱讀:http://nodejs.org/api/index.html
文檔資訊
- 著作權聲明:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
- 原文網址:http://blog.csdn.net/cdztop/article/details/33473299