Node.js快速入門

Node.js是什麼?

Node.js是建立在谷歌Chrome的JavaScript引擎(V8引擎)的Web應用程序框架。 它的最新版本是:v0.12.7(在編寫本教程時的版本)。Node.js在官方網站的定義文件內容如下:

Node.js® is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

Node.js自帶運行時環境可在Javascript腳本的基礎上可以解釋和執行(這類似於JVM的Java字節碼)。這個運行時允許在瀏覽器以外的任何機器上執行JavaScript代碼。由於這種運行時在Node.js上,所以JavaScript現在可以在服務器上並執行。

Node.js還提供了各種豐富的JavaScript模塊庫,它極大簡化了使用Node.js來擴展Web應用程序的研究與開發。

Node.js = 運行環境+ JavaScript庫

Node.js特性

  • Node.js庫的異步和事件驅動的API全部都是異步就是非阻塞。它主要是指基於Node.js的服務器不會等待API返回的數據。服務器移動到下一個API調用,Node.js發生的事件通知機制後有助於服務器獲得從之前的API調用的響應。

  • 非常快的內置谷歌Chrome的V8 JavaScript引擎,Node.js庫代碼執行是非常快的。

  • 單線程但高度可擴展 - Node.js使用具有循環事件單線程模型。事件機制有助於服務器在一個非阻塞的方式響應並使得服務器高度可擴展,而不是創建線程限制來處理請求的傳統服務器。Node.js使用單線程的程序,但可以提供比傳統的服務器(比如Apache HTTP服務器)的請求服務數量要大得多。

  • 沒有緩衝 - Node.js的應用從來不使用緩衝任何數據。這些應用只是輸出數據在塊中。

  • 許可證協議 - Node.js 在 MIT 協議 下發布

都有誰在使用Node.js?

以下是包含正在使用node.js的項目,應用和公司,一個詳盡的清單請點擊 github維基鏈接查看,這些清單裏包括:eBay, General Electric, GoDaddy, Microsoft, PayPal, Uber, Wikipins, Yahoo!, Yammer 並越來越多加入繼續擴大這個列表:使用NodeJS的項目, 應用和公司

概念

下圖描述了 Node.js 的一些重要組成部分,我們將詳細的在後續章節進行討論。

Node.js快速入門

在哪裏可以使用Node.js?

以下是Node.js證明自己完美的技術的合作伙伴的領域。

  • I/O 綁定應用程序

  • 數據流應用

  • 數據密集型實時應用(DIRT)

  • JSON API的應用程序

  • 單頁面應用

在哪些地方不要使用Node.js?

不建議使用Node.js的就是針對CPU密集型應用。

Node.js - 環境安裝配置

如果願意安裝設置Node.js環境,需要計算機上提供以下兩個軟件:

一、文本編輯器

二、Node.js二進制安裝包

文本編輯器

這將用來編寫程序代碼。 一些編輯器包括:Windows記事本,OS Edit命令,Brief, Epsilon, EMACS和VIM或vi。

文本編輯器的名稱和版本的在不同的操作系統可能不太相同。例如,記事本可用在Windows,VIM或vi可以在Windows以及Linux或UNIX上使用。

編輯器創建的文件稱爲源文件幷包含程序的源代碼。 對於Node.js的程序的源文件名通常命名擴展是 ".js".

在開始編程之前,請確保文本編輯器可用,並且有足夠的經驗來寫計算機程序,將其保存在一個文件,如:helloworld.js,編譯並執行。

Node.js 運行時

編寫源文件中的源代碼只需知道了解JavaScript。Node.js解釋器將用於解釋和執行JavaScript代碼。

Node.js的發行版以二進制安裝在SunOS,Linux,Mac OS X和Windows的32位(386)和64位(AMD64)的x86處理器架構操作系統。

以下部分將指導如何將Node.js的二進制分發版安裝在各種操作系統上。

下載Node.js的歸檔文件

下載最新版本Node.js的安裝歸檔文件在: Node.js 下載. 在寫這篇教程的時候,下載的是 node-v0.12.7-x64.msi 並複製到「桌面」。

OS

Archive name

Windows

node-v0.12.7-x64.msi

Linux

node-v0.12.7-linux-x86.tar.gz

Mac

node-v0.12.7-darwin-x86.tar.gz

SunOS

node-v0.12.7-sunos-x86.tar.gz

在UNIX/Linux/Mac OS X和SunOS上安裝(可選)

解壓縮下載歸檔文件到 /usr/local, 創建一個NodeJs樹 /usr/local/nodejs. 例如:

tar -C /usr/local -xzf node-v0.12.0-linux-x86.tar.gz

添加 /usr/local/nodejs 到PATH環境變量。

OS

輸出

Linux

export PATH=$PATH:/usr/local/nodejs

Mac

export PATH=$PATH:/usr/local/nodejs

FreeBSD

export PATH=$PATH:/usr/local/nodejs

在Windows上安裝Node.js(本教程中使用)

使用MSI文件,並按照提示安裝node.js,默認情況下,安裝程序將 Node.js 發行到 C:\Program Files\nodejs. 但這裏我們需要修改安裝路徑到:D:\yiibai_worksp\nodejs,並將 D:\yiibai_worksp\nodejs 目錄添加到Window系統的PATH環境變量中。重新啓動打開命令提示符,以使更改生效。

第一步:雙擊下載的  「node-v0.12.7-x64.msi" 文件,出現提示安裝界面:

Node.js快速入門

第二步:選擇安裝目錄,這裏安裝在目錄 D:\yiibai_worksp\nodejs 中,如下圖:

Node.js快速入門

第三步:選擇安裝的模塊和功能,這裏全部安裝,並添加到系統環境變量,如下圖所示:

Node.js快速入門

最後一步:安裝完成!

Node.js快速入門

驗證安裝:執行文件

創建一個js文件名爲test.js 在 D:\>yiibai_worksp\nodejs.

File: test.js

console.log("Hello World")

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出結果:

Node.js快速入門

Node.js - 第一個應用程序

在使用 Node.js 創建 Hello World ! 應用程序之前, 讓我們看看Node.js的應用程序的組成部分。Node.js應用程序由以下三個重要部分組成:

  • 導入所需模塊: 使用require指令來加載javascript模塊

  • 創建一個服務器: 服務器這將聽監聽在Apache HTTP服務器客戶端的請求。

  • 讀取請求並返回響應: 在前面的步驟中創建的服務器將響應讀取由客戶機發出的HTTP請求(可以是一個瀏覽器或控制檯)並返回響應。

創建Node.js應用

步驟 1:導入所需的包

使用require指令來加載 HTTP 模塊。

var http = require("http")

步驟 2:使用http.createServer方法創建HTTP服務器。通過參數函數請求並響應。編寫示例實現返回「Hello World」。服務器在8081端口監聽。

http.createServer(function (request, response) {
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// send the response body as "Hello World"
response.end('Hello World\n');
}).listen(8081);
// console will print the message
console.log('Server running at http://127.0.0.1:8081/');

步驟 3: 創建一個 js 文件在 helloworld.js 在 D:\>yiibai_worksp.

File: helloworld.js

var http = require("http")
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');

現在運行 helloworld.js 看到結果:

D:\yiibai_worksp\nodejs>node helloworld.js

驗證輸出,服務器應用已經啓動!

Server running at http://127.0.0.1:8081/

向Node.js服務器發出請求

打開瀏覽器(IE),在地址欄中輸入:http://127.0.0.1:8081/ 在瀏覽器中,看看下面的結果。

Node.js快速入門

Node.js - REPL

REPL代表讀取評估和演示打印循環,它就像 Window 下的控制檯的計算機環境,或 Unix/Linux 系統的 Shell命令輸入響應輸出。 Node.js或Node 捆綁了一個REPL環境。可執行以下任務。

  • 讀取- 讀取用戶的輸入,解析輸入的JavaScript數據結構並存儲在內存

  • 計算- 採取並評估計算數據結構

  • 打印- 打印結果

  • 循環 - 循環上面的命令,直到用戶按Ctrl-C兩次終止

Node 的REPL 與 Node.js 的實驗代碼非常有用,用於調試JavaScript代碼。

特點

REPL可以通過簡單地在shell/控制檯運行node不帶任何參數來啓動。

D:\yiibai_worksp\nodejs> node

可以看到REPL 命令提示符:

D:\yiibai_worksp\nodejs> node

簡單的表達式

讓我們嘗試在REPL命令提示符下執行簡單的數學運算:

D:\yiibai_worksp\nodejs>node

1 + 3
4
1 + ( 2 * 3 ) - 4
3

使用變量

使用變量儲存值後並打印。如果不使用var關鍵字,那麼值存儲在變量並打印。而如果使用var關鍵字存儲值,那麼不會打印。稍後,可以使用這兩個變量。使用console.log()打印來任何東西

D:\yiibai_worksp\nodejs> node

x = 10
10
var y = 10
undefined
x + y
20
console.log("Hello World")
Hello Workd
undefined

多行表達

Node REPL支持類似於JavaScript的多表達。請參閱下列do-while循環:

D:\yiibai_worksp\nodejs> 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自動檢查表達式的連續性。

下劃線變量

使用_得到最後的結果。

D:\yiibai_worksp\nodejs> 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 twice - 終止 Node REPL

  • ctrl + d - 終止 Node REPL

  • Up/Down Keys - 查看命令歷史記錄和修改以前的命令

  • tab Keys - 當前命令列表

  • .help - 列出所有命令

  • .break - 退出多行表達

  • .clear - 從多行表達式退出

  • .save - 當前 Node REPL會話保存到一個文件

  • .load - 加載文件的內容到當前Node REPL會話

D:\yiibai_worksp\nodejs> node

var x = 10
undefined
var y = 20
undefined
x + y
30
var sum = _
undefined
console.log(sum)
30
undefined
.save test.js
Session saved to:test.js
.load test.js
var x = 10
undefined
var y = 20
undefined
x + y
30
var sum = _
undefined
console.log(sum)
30
undefined

Node.js - npm

npm 表示節點程序包管理器。npm 提供以下兩個主要功能:

  • Node.js包/模塊的在線軟件倉庫,可通過搜索 search.nodejs.org

  • 命令行實用程序安裝包,作爲Node.js版本管理和依賴包管理。

Node.js v0.6.3版本後纔開始捆綁 npm 安裝。爲了驗證,打開控制檯,然後輸入以下命令並查看結果:

D:\yiibai_worksp\nodejs>npm --version
2.11.3

全局VS本地安裝

默認情況下,NPM安裝在任何依賴性的本地模式。在這裏,本地模式指的是包在安裝目錄node_modules,位於Node應用的文件夾中。本地部署的包都可以通過require() 訪問 。

全局安裝的軟件包/依賴存儲在<用戶目錄>/npm目錄。 這種依賴關係可以在命令行中使用Node.js的(命令行界面)任何功能,但不能使用require()在Node直接應用導入。

我們來開始安裝明確,使用本地來安裝一個流行的Web框架。

D:\yiibai_worksp\nodejs>npm install express
express@4.11.2 node_modules\express
|-- merge-descriptors@0.0.2
|-- utils-merge@1.0.0
|-- methods@1.1.1
|-- escape-html@1.0.1
|-- fresh@0.2.4
|-- cookie@0.1.2
|-- range-parser@1.0.2
|-- media-typer@0.3.0
|-- cookie-signature@1.0.5
|-- vary@1.0.0
|-- finalhandler@0.3.3
|-- parseurl@1.3.0
|-- serve-static@1.8.1
|-- content-disposition@0.5.0
|-- path-to-regexp@0.1.3
|-- depd@1.0.0
|-- qs@2.3.3
|-- debug@2.1.1 (ms@0.6.2)
|-- send@0.11.1 (destroy@1.0.3, ms@0.7.0, mime@1.2.11)
|-- on-finished@2.2.0 (ee-first@1.1.0)
|-- type-is@1.5.7 (mime-types@2.0.9)
|-- accepts@1.2.3 (negotiator@0.5.0, mime-types@2.0.9)
|-- etag@1.5.1 (crc@3.2.1)
|-- proxy-addr@1.0.6 (forwarded@0.1.0, ipaddr.js@0.1.8)

一旦NPM完成下載,可以通過查看 D:\yiibai_worksp\nodejs\node_modules 的內容驗證,或鍵入以下命令:

D:\yiibai_worksp\nodejs> npm ls
D:\yiibai_worksp\nodejs
|-- express@4.11.2
|-- accepts@1.2.3
| |-- mime-types@2.0.9
| | |-- mime-db@1.7.0
| |-- negotiator@0.5.0
|-- content-disposition@0.5.0
|-- cookie@0.1.2
|-- cookie-signature@1.0.5
|-- debug@2.1.1
| |-- ms@0.6.2
|-- depd@1.0.0
|-- escape-html@1.0.1
|-- etag@1.5.1
| |-- crc@3.2.1
|-- finalhandler@0.3.3
|-- fresh@0.2.4
|-- media-typer@0.3.0
|-- merge-descriptors@0.0.2
|-- methods@1.1.1
|-- on-finished@2.2.0
| |-- ee-first@1.1.0
|-- parseurl@1.3.0
|-- path-to-regexp@0.1.3
|-- proxy-addr@1.0.6
| |-- forwarded@0.1.0
| |-- ipaddr.js@0.1.8
|-- qs@2.3.3
|-- range-parser@1.0.2
|-- send@0.11.1
| |-- destroy@1.0.3
| |-- mime@1.2.11
| |-- ms@0.7.0
|-- serve-static@1.8.1
|-- type-is@1.5.7
| |-- mime-types@2.0.9
| |-- mime-db@1.7.0
|-- utils-merge@1.0.0
|-- vary@1.0.0

上面列出的內容很長,這裏省略了一部分。

現在,讓我們嘗試安裝明確,使用全局安裝流行Web框架。

D:\yiibai_worksp\nodjs> npm install express - g

一旦NPM完成下載,可以通過查看<用戶目錄>/nmp/node_modules中的內容來驗證。或輸入以下命令:

D:\yiibai_worksp\nodejs> npm ls -g

以上可能會遇網絡問題無法安裝,需要翻牆。

安裝模塊

安裝模塊很簡單,只要鍵入以下命令。

D:\yiibai_worksp\nodejs> npm install express

現在,可以在 js 文件中使用它,如下:

var express = require('express');

package.json 包

package.json是存在於任何Node應用程序/模塊的根目錄,並用於定義一個包的屬性。 讓我們打開 package.json express包在 D:\yiibai_worksp\nodejs\node_modules\express\

{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.11.2",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"contributors": [
{
"name": "Aaron Heckmann",
"email": "aaron.heckmann+github@gmail.com"
},
{
"name": "Ciaran Jessup",
"email": "ciaranj@gmail.com"
},
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Guillermo Rauch",
"email": "rauchg@gmail.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com"
},
{
"name": "Roman Shtylman",
"email": "shtylman+expressjs@gmail.com"
},
{
"name": "Young Jae Sim",
"email": "hanul@hanul.me"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/strongloop/express"
},
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
"sinatra",
"web",
"rest",
"restful",
"router",
"app",
"api"
],
"dependencies": {
"accepts": "1.2.3",
"content-disposition": "0.5.0",
"cookie-signature": "1.0.5",
"debug": "
2.1.1",
"depd": "1.0.0",
"escape-html": "1.0.1",
"etag": "
1.5.1",
"finalhandler": "0.3.3",
"fresh": "0.2.4",
"media-typer": "0.3.0",
"methods": "1.1.1",
"on-finished": "
2.2.0",
"parseurl": "1.3.0",
"path-to-regexp": "0.1.3",
"proxy-addr": "
1.0.6",
"qs": "2.3.3",
"range-parser": "1.0.2",
"send": "0.11.1",
"serve-static": "
1.8.1",
"type-is": "1.5.6",
"vary": "
1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2",
"utils-merge": "1.0.0"
},
"devDependencies": {
"after": "0.8.1",
"ejs": "2.1.4",
"istanbul": "0.3.5",
"marked": "0.3.3",
"mocha": "2.1.0",
"should": "
4.6.2",
"supertest": "0.15.0",
"hjs": "
0.0.6",
"body-parser": "1.11.0",
"connect-redis": "
2.2.0",
"cookie-parser": "1.3.3",
"express-session": "
1.10.2",
"jade": "1.9.1",
"method-override": "
2.3.1",
"morgan": "1.5.1",
"multiparty": "
4.1.1",
"vhost": "~3.0.0"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/"
},
"gitHead": "63ab25579bda70b4927a179b580a9c580b6c7ada",
"bugs": {
"url": "https://github.com/strongloop/express/issues"
},
"_id": "express@4.11.2",
"_shasum": "8df3d5a9ac848585f00a0777601823faecd3b148",
"_from": "express@*",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "shtylman",
"email": "shtylman@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "aredridel",
"email": "aredridel@nbtsc.org"
},
{
"name": "strongloop",
"email": "callback@strongloop.com"
},
{
"name": "rfeng",
"email": "enjoyjava@gmail.com"
}
],
"dist": {
"shasum": "8df3d5a9ac848585f00a0777601823faecd3b148",
"tarball": "http://registry.npmjs.org/express/-/express-4.11.2.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/express/-/express-4.11.2.tgz",
"readme": "ERROR: No README data found!"
}

Package.json 屬性

  • name - 包的名稱

  • version - 包的版本

  • description - 包的描述

  • homepage - 包的網站主頁

  • author - 包的作者

  • contributors - 包的貢獻者的名稱列表

  • dependencies - 依賴性列表。npm自動安裝所有在node_module文件夾中的包提到的依賴關係。

  • repository - 包的存儲庫類型和URL

  • main - 包的入口點

  • keywords - 關鍵字

卸載模塊

請使用以下命令卸載模塊。

D:\yiibai_worksp\nodejs> npm uninstall express

當npm卸載的軟件包,可以通過查看<用戶目錄>/npm/node_modules 的內容驗證。或鍵入以下命令:

D:\yiibai_worksp\nodejs> npm ls

更新模塊

更新的package.json並更改其版本依賴關係進行更新,運行以下命令。

D:\yiibai_worksp\nodejs> npm update

搜索模塊

使用npm搜索包名。

D:\yiibai_worksp\nodejs>npm search express

創建一個模塊

創建模塊需要要生成package.json。讓我們使用 npm 產生 package.json。

D:\yiibai_worksp\nodejs> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See 'npm help json' for definitive documentation on these fields
and exactly what they do.

Use 'npm install --save' afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (Nodejs_WorkSpace)

一旦的 package.json 產生。使用一個有效的電子郵件地址在npm庫網站上註冊自己,使用如面的命令。

D:\yiibai_worksp\nodejs> npm adduser

現在,是時候來發布模塊了:

D:\yiibai_worksp\nodejs> npm publish

Node.js - 回調概念

什麼是回調?

回調是一種異步相當於一個函數。回調函數被調用在完成既定任務。Node大量使用了回調。Node所有的API寫的都是支持回調的這樣一種方式。例如,一個函數讀取一個文件可能開始讀取文件,並立即返回控制到執行環境 使得下一個指令可以馬上被執行。一旦文件 I/O 完成,它會調用回調函數,同時傳遞迴調函數,該文件作爲參數的內容。因此不會有堵塞或等待文件I/O。這使得Node.js高度可擴展,因此可以處理大量的請求,而無需等待任何函數來返回結果。

阻塞代碼示例

創建一個 txt 文件:test.txt 在 D:\>yiibai_worksp\nodejs 目錄

Yiibai.Com

創建一個名爲test.js 的js文件在 D:\>yiibai_worksp\nodejs

var fs = require("fs");
var data = fs.readFileSync('test.txt');
console.log(data.toString());
console.log("Program Ended");

現在運行 test.js 看到的結果:

D:\yiibai_worksp\nodejs>node test.js

驗證輸出結果:

Yiibai.com
Program Ended

非阻塞代碼示例

創建一個 txt 文件:test.txt 在 D:\>yiibai_worksp\nodejs 目錄

Yiibai.Com

更新 test.js 的內容在目錄D:\>yiibai_worksp\nodejs

var fs = require("fs");

fs.readFile('test.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
});
console.log("Program Ended");

現在運行 test.js 看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出

Program Ended
Yiibai.Com

事件循環概述

Node JS是單線程應用程序,但它通過事件和回調的概念,支持併發。NodeJS的每一個API都是異步的,作爲一個單獨的線程,它使用異步函數調用來維護併發。Node使用觀察者模式。Node線程保持一個事件循環,每當任何任務完成後得到結果,它觸發通知事件偵聽函數來執行相應的事件。

事件驅動編程

Node.js使用大量事件,這也是爲什麼Node.js相對於其他類似技術比較快的原因之一。當Node啓動其服務器,就可以簡單地初始化其變量,聲明函數,然後等待事件的發生。

雖然事件似乎類似於回調。不同之處在於當回調函數被調用異步函數返回結果,其中的事件處理工作在觀察者模式。監聽事件函數作爲觀察者。每當一個事件被解僱,其監聽函數開始執行。Node.js有多個內置的事件。 主要扮演者是 EventEmitter,可使用以下語法導入。

//import events module
var events = require('events');
//create an eventEmitter object
var eventEmitter = new events.EventEmitter();

示例

創建一個 js 文件名爲 test.js 的文件在D:\>yiibai_worksp\nodejs

File: test.js

//import events module
var events = require('events');
//create an eventEmitter object
var eventEmitter = new events.EventEmitter();

//create a function connected which is to be executed
//when 'connection' event occurs
var connected = function connected() {
console.log('connection succesful.');

// fire the data_received event
eventEmitter.emit('data_received.');
}

// bind the connection event with the connected function
eventEmitter.on('connection', connected);

// bind the data_received event with the anonymous function
eventEmitter.on('data_received', function(){
console.log('data received succesfully.');
});

// fire the connection event
eventEmitter.emit('connection');

console.log("Program Ended.");

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出。服務器已經啓動

connection succesful.
data received succesfully.
Program Ended.

Node應用程序如何工作?

在Node 應用,任何異步函數接受回調作爲最後的參數,並回調函數接受錯誤作爲第一個參數。我們再看一下前面的例子。

var fs = require("fs");

fs.readFile('test.txt', function (err, data) {
if (err){
console.log(err.stack);
return;
}
console.log(data.toString());
});
console.log("Program Ended");

這裏fs.readFile是一個異步函數,其目的是用於讀取文件。 如果在文件的讀取發生了錯誤,則err 對象將包含相應的錯誤,否則data將包含該文件的內容。readFile通過err和data到回調函數後,文件讀取操作完成。

Node.js - 事件發射器

EventEmitter類在於事件的模塊。它通過通俗易懂的語法如下:

//import events module
var events = require('events');
//create an eventEmitter object
var eventEmitter = new events.EventEmitter();

當EventEmitter實例出現任何錯誤,它會發出「error」事件。當新的監聽器添加,'newListener'事件被觸發,當一個監聽器被刪除,'removeListener「事件被觸發。

EventEmitter提供多種屬性,如:on和emit。on屬性用於綁定與該事件的函數,而 emit 用於觸發一個事件。

方法

Sr. No.

方法

描述

1

addListener(event, listener)

指定事件添加一個監聽器到監聽器數組的結尾。不用檢查查看監聽器是否已經添加。多個調用傳遞事件和監聽器的相同組合將導致在監聽器被多次添加。返回發射器,因此調用可以鏈接。

2

on(event, listener)

添加一個監聽器到指定事件的監聽器數組的結尾。沒有進行檢查以查看是否收聽已經添加。多個調用傳遞事件和監聽器的相同的組合將導致監聽器被多次添加。 返回發射器,因此調用可以鏈接。

3

once(event, listener)

增加了一次監聽事件。該監聽器只被調用在下一次的事件被觸發後它將被刪除。 返回發射器,因此調用可鏈接。

4

removeListener(event, listener)

返回發射器,因此調用可鏈接。注意:改變數組索引的監聽器數組在監聽器後面。removeListener從監聽數組中刪除一個監聽器的一個實例。如果單個監聽器已多次添加到監聽器數組中指定的事件,那麼removeListener被多次調用刪除每個實例。 返回發射器,因此調用可鏈接。

5

removeAllListeners([event])

刪除所有監聽器,或者那些指定的事件。這不是一個好主意,刪除監聽器在其他地方添加代碼,特別是當它在發射器但沒有創建(如套接字或文件流)。返回發射器,因此調用可鏈接。

6

setMaxListeners(n)

默認情況下,如果超過10監聽器添加特定事件EventEmitters會打印警告。這是一個有用的默認這有助於發現內存泄漏。顯然,並非所有的發射器應限制在10個。此功能可以設置增加。設置爲零無限。

7

listeners(event)

返回監聽指定事件的數組。

8

emit(event, [arg1], [arg2], [...])

爲了與提供的參數執行每個監聽器。如果事件有監聽器返回true,否則爲false。

類方法

Sr. No.

方法

描述

1

listenerCount(emitter, event)

返回對於一個給定事件的監聽器的數量。

事件

Sr. No.

事件名稱

參數

描述

1

newListener

  • event - 字符串 - 事件名稱

  • listener- 函數-事件處理函數

事件在任何時間發出添加監聽器。當該事件被觸發時,監聽器可能還沒有爲事件添加到監聽器的數組。

2

removeListener

  • event - 字符串事件名稱

  • listener- 函數的事件處理函數

事件在任何時候發出刪除一個監聽器。當該事件被觸發時,監聽器可能還沒有爲事件添加到監聽器的數組。

示例

創建一個js文件名爲test.js,在 D:\>yiibai_worksp\nodejs

File: test.js

var events = require('events');
var eventEmitter = new events.EventEmitter();

//listener #1
var listner1 = function listner1() {
console.log('listner1 executed.');
}

//listener #2
var listner2 = function listner2() {
console.log('listner2 executed.');
}

// bind the connection event with the listner1 function
eventEmitter.addListener('connection', listner1);

// bind the connection event with the listner2 function
eventEmitter.on('connection', listner2);

var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");

// fire the connection event
eventEmitter.emit('connection');

// remove the binding of listner1 function
eventEmitter.removeListener('connection', listner1);
console.log("Listner1 will not listen now.");

// fire the connection event
eventEmitter.emit('connection');

eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");

console.log("Program Ended.");

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出。服務器已經啓動

2 Listner(s) listening to connection event
listner1 executed.
listner2 executed.
Listner1 will not listen now.
listner2 executed.
1 Listner(s) listening to connection event
Program Ended.

Node.js - 緩衝模塊

緩衝器模塊可以被用來創建緩衝區和SlowBuffer類。緩衝模塊可以使用以下語法導入。

var buffer = require("buffer")

Buffer 類

Buffer類是一個全局類,可以在應用程序,無需導入緩衝模塊進行訪問。緩衝區是一種整數數組並對應於原始存儲器V8堆以外分配。 緩衝區不能調整大小。

類方法

Sr. No.

方法

參數

描述

1

Buffer.isEncoding(encoding)

  • 編碼字符串 - 編碼字符串測試

如果編碼是一種有效的編碼參數,返回true,否則返回false

2

Buffer.isBuffer(obj)

  • obj Object

  • Return: Boolean

測試 obj 是否爲一個緩衝區

3

Buffer.byteLength(string[, encoding])

  • string字符串

  • 編碼字符串,可選,默認: 'utf8'

  • Return: Number

給出了一個字符串的實際字節長度。encoding 的默認值是 'utf8'.這與String.prototype.length是不一樣的,因爲它返回字符串中的字符的數目。

4

Buffer.concat(list[, totalLength])

  • 緩衝區列表數組列表對象到Concat

  • 當串聯後緩衝區的數目是totalLength總長度

返回一個緩衝器是連接所有的緩衝器列表中在一起的結果。

5

Buffer.compare(buf1, buf2)

  • buf1 Buffer

  • buf2 Buffer

同樣作爲buf1.compare(buf2)。用於排序緩衝器數組。

示例

創建一個js文件名爲test.js,在 D:\>yiibai_worksp\nodejs

File: test.js

//create a buffer
var buffer = new Buffer(26);
console.log("buffer length: " + buffer.length);

//write to buffer
var data = "YiiBai.com";
buffer.write(data);
console.log(data + ": " + data.length + " characters, " + Buffer.byteLength(data, 'utf8') + " bytes");

//slicing a buffer
var buffer1 = buffer.slice(0,14);
console.log("buffer1 length: " + buffer1.length);
console.log("buffer1 content: " + buffer1.toString());

//modify buffer by indexes
for (var i = 0 ; i < 26 ; i++) {
buffer[i] = i + 97; // 97 is ASCII a
}
console.log("buffer content: " + buffer.toString('ascii'));

var buffer2 = new Buffer(4);

buffer2[0] = 0x3;
buffer2[1] = 0x4;
buffer2[2] = 0x23;
buffer2[3] = 0x42;

//reading from buffer
console.log(buffer2.readUInt16BE(0));
console.log(buffer2.readUInt16LE(0));
console.log(buffer2.readUInt16BE(1));
console.log(buffer2.readUInt16LE(1));
console.log(buffer2.readUInt16BE(2));
console.log(buffer2.readUInt16LE(2));

var buffer3 = new Buffer(4);
buffer3.writeUInt16BE(0xdead, 0);
buffer3.writeUInt16BE(0xbeef, 2);

console.log(buffer3);

buffer3.writeUInt16LE(0xdead, 0);
buffer3.writeUInt16LE(0xbeef, 2);

console.log(buffer3);
//convert to a JSON Object
var json = buffer3.toJSON();
console.log("JSON Representation : ");
console.log(json);

//Get a buffer from JSON Object
var buffer6 = new Buffer(json);
console.log(buffer6);

//copy a buffer
var buffer4 = new Buffer(26);
buffer.copy(buffer4);
console.log("buffer4 content: " + buffer4.toString());

//concatenate a buffer
var buffer5 = Buffer.concat([buffer,buffer4]);
console.log("buffer5 content: " + buffer5.toString());

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出結果

buffer length: 26
YiiBai.com: 18 characters, 18 bytes
buffer1 length: 14
buffer1 content: YiiBai
buffer content: abcdefghijklmnopqrstuvwxyz
772
1027
1059
8964
9026
16931


buffer4 content: abcdefghijklmnopqrstuvwxyz
buffer5 content: abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz

Node.js - 數據流

什麼是數據流?

數據流是從源數據讀取或寫入數據到目標對象以。在節點中,有四種類型的流:

  • Readable - 數據流,其是用於讀操作

  • Writable - 數據流,用在寫操作

  • Duplex - 數據流,其可以用於讀取和寫入操作

  • Transform - 雙相類型流,輸出基於輸入進行計算

每種類型的流是EventEmitter,並且一次引發幾個事件。例如,一些常用的事件是:

  • data - 當有數據可讀取時觸發此事件

  • end - 當沒有更多的數據讀取時觸發此事件

  • error - 當有錯誤或接收數據寫入時觸發此事件

  • finish - 當所有數據已刷新到底層系統時觸發此事件

從數據流中讀取

創建一個txt文件名爲test.txt,在 D:\>yiibai_worksp\nodejs

Yiibai.Com

創建一個文件 test.js 在目錄 D:\>yiibai_worksp\nodejs

var fs = require("fs");
var data = '';
//create a readable stream
var readerStream = fs.createReadStream('test.txt');

//set the encoding to be utf8.
readerStream.setEncoding('UTF8');

//handle stream events
readerStream.on('data', function(chunk) {
data += chunk;
});

readerStream.on('end',function(){
console.log(data);
});

readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("Program Ended");

現在運行 test.js 看到的結果如下:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出結果:

Program Ended
Yiibai.Com

寫入到流

更新文件 test.js 內容在目錄 D:\>yiibai_worksp\nodejs

var fs = require("fs");
var data = 'Yiibai.Com';
//create a writable stream
var writerStream = fs.createWriteStream('test1.txt');

//write the data to stream
//set the encoding to be utf8.
writerStream.write(data,'UTF8');

//mark the end of file
writerStream.end();

//handle stream events
writerStream.on('finish', function() {
console.log("Write completed.");
});

writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("Program Ended");

現在運行 test.js 看到的結果:

D:\yiibai_worksp\nodejs>node test.js

驗證輸出:

Program Ended
Write completed.

打開文件 test1.txt 在目錄 D:\>yiibai_worksp\nodejs. 驗證輸出結果:

Yiibai.Com

管道流

管道是一種機制,一個流的輸出連接到另一個流(作爲另外一個流的輸入)。它通常用來從一個流中獲取數據,並通過該流輸出到另一個流。管道沒有對操作限制。考慮上面的例子中,在這裏我們使用readerStream 讀取test.txt的內容,並使用 writerStream 寫入 test1.txt。現在,我們將用管道來簡化操作,或者從一個文件中讀取並寫入到另一個文件。

更新 test.js 文件的內容,在目錄 D:\>yiibai_worksp\nodejs, 如下:

var fs = require("fs");

//create a readable stream
var readerStream = fs.createReadStream('test.txt');

//create a writable stream
var writerStream = fs.createWriteStream('test2.txt');

//pipe the read and write operations
//read test.txt and write data to test2.txt
readerStream.pipe(writerStream);

console.log("Program Ended");

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出的結果:

Program Ended

打開文件 test2.txt 在 D:\>yiibai_worksp\nodejs. 驗證輸出結果:

Yiibai.Com

Node.js - 文件系統

fs模塊用於文件I/O。 fs模塊可以使用以下語法導入。

var fs = require("fs")

同步 vs 異步

每一個fs模塊的方法都有同步和異步形式。異步方法接受一個最後的參數爲完成回調函數,而回調函數的第一個參數是錯誤。它優選使用異步方法來代替同步方法,前者從未阻塞程序執行,而後者則會阻塞。

示例

創建一個js文件名爲test.js 在目錄 D:\>yiibai_worksp\nodejs 

File: test.js

var fs = require("fs");

//Asynchronous read
fs.readFile('test.txt', function (err, data) {
if (err) return console.error(err);
console.log("Asynchronous read: " + data.toString());
});

//Synchronous read
var data = fs.readFileSync('test.txt');
console.log("Synchronous read: " + data.toString());

console.log("Program Ended");

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出結果:

Synchronous read: Yiibai.Com
Program Ended
Asynchronous read: Yiibai.Com

方法

Sr. No.

方法

描述

1

fs.rename(oldPath, newPath, callback)

rename()異步,不帶參數可能是個例外,提供完成回調

2

fs.ftruncate(fd, len, callback)

ftruncate()異步,不帶參數可能是個例外,提供完成回調

3

fs.ftruncateSync(fd, len)

 ftruncate() 同步

4

fs.truncate(path, len, callback)

truncate()異步. 沒有參數時它可能是例外,提供給完成回調。

5

fs.truncateSync(path, len)

truncate()同步

6

fs.chown(path, uid, gid, callback)

chown()異步. 沒有參數時它可能是例外,提供給完成回調。

7

fs.chownSync(path, uid, gid)

chown() 同步

8

fs.fchown(fd, uid, gid, callback)

fchown()異步. 沒有參數時它可能是例外,提供給完成回調。

9

fs.fchownSync(fd, uid, gid)

fchown()異步

10

fs.lchown(path, uid, gid, callback)

lchown()異步. 沒有參數時它可能是例外,提供給完成回調。

11

fs.lchownSync(path, uid, gid)

lchown()同步

12

fs.chmod(path, mode, callback)

chmod()異步. 沒有參數時它可能產生例外,提供給完成回調。

13

fs.chmodSync(path, mode)

chmod() 同步

14

fs.fchmod(fd, mode, callback)

fchmod() 異步. 沒有參數時它可能產生例外,提供給完成回調。

15

fs.fchmodSync(fd, mode)

fchmod() 同步

16

fs.lchmod(path, mode, callback)

lchmod() 異步, 沒有參數時它可能產生例外,提供給完成回調。僅可在Mac OS X 上使用

17

fs.lchmodSync(path, mode)

 lchmod() 同步

18

fs.stat(path, callback)

stat() 同步,回調函數得到兩個參數(err, stats) ,其中stats是一個fs.Stats對象

19

fs.lstat(path, callback)

lstat()異步,回調函數得到兩個參數(err, stats),其中stats是一個fs.Stats對象。lstat()等同於stat(),不同之處在於,如果路徑path是一個符號鏈接,那麼鏈接本身是stat-ed,而不是指文件。

20

fs.fstat(fd, callback)

fstat() 異步. 回調函數得到兩個參數 (err, stats) ,其中統計數據是一個fs.Stats對象。fstat()等同於stat(),除了該文件是stat-ed 由文件描述符fd指定。

21

fs.statSync(path)

stat()同步,返回fs.Stats的一個實例。

22

fs.lstatSync(path)

lstat()同步,返回fs.Stats的一個實例。

23

fs.fstatSync(fd)

 fstat() 同步,返回fs.Stats的一個實例。

24

fs.link(srcpath, dstpath, callback)

link() 異步.  沒有參數時它可能產生例外,提供給完成回調。

25

fs.linkSync(srcpath, dstpath)

link() 同步

26

fs.symlink(srcpath, dstpath[, type], callback)

symlink()異步,沒有參數時它可能是例外,提供給完成回調。該類型參數可以設置爲 'dir', 'file', 或 'junction' (默認爲'file') ,只適用於Windows(忽略其他平臺)。請注意,Windows結點需要目標路徑是絕對的。當使用'junction',目標參數將自動歸絕對路徑。

27

fs.symlinkSync(srcpath, dstpath[, type])

symlink()同步

28

fs.readlink(path, callback)

readlink()同步,回調函數得到兩個參數(err, linkString)。

29

fs.realpath(path[, cache], callback)

realpath() 異步. 回調函數得到兩個參數(err, resolvedPath)。可以使用process.cwd解決相對路徑。緩存cache是一個對象字面量,可以用來強制一個特定路徑解析或避免額外的fs.stat調用真正的路徑映射路徑。

30

fs.realpathSync(path[, cache])

realpath()同步,返回解決路徑。

31

fs.unlink(path, callback)

unlink()異步,沒有參數時它可能產生例外,提供給完成回調。

32

fs.unlinkSync(path)

 unlink()同步

33

fs.rmdir(path, callback)

rmdir()異步,沒有參數時它可能產生例外,提供給完成回調。

34

fs.rmdirSync(path)

rmdir()同步

35

fs.mkdir(path[, mode], callback)

mkdir(2)異步,模式默認爲0777。

36

fs.mkdirSync(path[, mode])

mkdir()同步

37

fs.readdir(path, callback)

readdir(3) 同步,讀取目錄中的內容。回調函數得到兩個參數 (err, files) ,其中文件是文件的數組名稱在目錄中,不包括 '.' 和 '..'.

38

fs.readdirSync(path)

readdir()同步,返回文件名數組不含 '.' 和 '..'.

39

fs.close(fd, callback)

close() 同步,沒有參數時它可能產生例外,提供給完成回調。

40

fs.closeSync(fd)

close() 同步

41

fs.open(path, flags[, mode], callback)

異步文件打開

42

fs.openSync(path, flags[, mode])

fs.open()同步

43

fs.utimes(path, atime, mtime, callback)

44

fs.utimesSync(path, atime, mtime)

改變所提供的路徑引用的文件的文件時間戳。

45

fs.futimes(fd, atime, mtime, callback)

46

fs.futimesSync(fd, atime, mtime)

改變由提供的文件的描述符所引用的文件的文件時間戳。

47

fs.fsync(fd, callback)

fsync(2) 異步,沒有參數時它可能產生例外,提供給完成回調。

48

fs.fsyncSync(fd)

fsync(2)同步

49

fs.write(fd, buffer, offset, length[, position], callback)

fd指定的文件寫緩衝器

50

fs.write(fd, data[, position[, encoding]], callback)

指定的fd寫入文件數據。如果數據不是一個緩衝區實例則該值將被強制轉換爲字符串。

51

fs.writeSync(fd, buffer, offset, length[, position])

fs.write()同步。返回寫入的字節數。

52

fs.writeSync(fd, data[, position[, encoding]])

fs.write()同步。返回寫入的字節數。

53

fs.read(fd, buffer, offset, length, position, callback)

從fd指定文件讀取數據。

54

fs.readSync(fd, buffer, offset, length, position)

fs.read同步。返回 bytesRead 讀取的數量。

55

fs.readFile(filename[, options], callback)

異步讀取文件的全部內容。

56

fs.readFileSync(filename[, options])

fs.readFile同步,返回文件名的內容。

57

fs.writeFile(filename, data[, options], callback)

異步數據寫入到文件,如果它已經存在則替換文件。數據可以是字符串或緩衝。

58

fs.writeFileSync(filename, data[, options])

fs.writeFile 同步

59

fs.appendFile(filename, data[, options], callback)

異步數據追加到文件,創建文件如果文件不存在。數據可以是字符串或緩衝。

60

fs.appendFileSync(filename, data[, options])

fs.appendFile同步

61

fs.watchFile(filename[, options], listener)

關注有關文件名更改,回調監聽器在每個被訪問的文件名時。

62

fs.unwatchFile(filename[, listener])

停止監視對於文件名的更改。如果指定監聽器,只有特定的監聽器被刪除。否則,所有監聽器都會刪除,已經有效地停止監聽文件名。

63

fs.watch(filename[, options][, listener])

關注文件名的變化,其中 filename 是一個文件或目錄。返回是一個 fs.FSWatcher 的對象。

64

fs.exists(path, callback)

測試給定的路徑通過使用文件系統檢查是否存在。然後調用回調參數爲真或假。

65

fs.existsSync(path)

fs.exists同步

66

fs.access(path[, mode], callback)

由path指定的文件測試用戶的權限。mode是一個可選整數,指定要執行輔助功能的檢查。

67

fs.accessSync(path[, mode])

fs.access同步。這將引發輔助功能失敗,否則什麼也不做。

68

fs.createReadStream(path[, options])

返回一個新的ReadStream對象

69

fs.createWriteStream(path[, options])

返回一個新的WriteStream對象

70

fs.symlink(srcpath, dstpath[, type], callback)

異步symlink(). 該類型參數可以設置爲'dir','file',或'junction'(默認爲「文件」),只適用於Windows(忽略其他平臺)。請注意,Windows交界點需要的目標路徑是絕對的。當使用'junction',目標參數將自動標準化爲絕對路徑。

標誌

標誌進行讀/寫操作是:

  • r - 打開文件進行讀取。如果該文件不存在發生異常。

  • r+ - 打開文件進行讀取和寫入。如果該文件不存在發生異常。

  • rs - 打開文件,用於讀取在同步方式。指示操作系統繞過本地文件系統高速緩存。這是對NFS掛載打開文件,因爲它可以讓你跳過潛在陳舊的本地緩存中很有用。它對I/O性能有非常現實的影響,除非需要它,否則不要使用此標誌。注意,這無法打開 fs.open() 到一個同步阻塞調用。如果這不是真想要的,那麼應該使用fs.openSync()。

  • rs+ - 打開文件進行讀取和寫入,告訴操作系統同步地打開它。 對於'rs'有關異步使用 - 要慎用。

  • w - 打開文件進行寫入。該文件被創建(如果它不存在)或截斷清空內容(如果存在)。

  • wx - 類似「w」,但如果路徑存在,則失敗。

  • w+ - 打開文件進行讀取和寫入。該文件被創建(如果它不存在)或截斷清空內容(如果存在)。

  • wx+ - 類似 「w+」,但如果路徑存在,則失敗

  • a - 打開文件進行追加。如果文件不存在,則創建該文件

  • ax - 類似「a」,但如果路徑存在則失敗

  • a+ - 打開文件進行讀取和追加內容。如果文件不存在,則創建該文件

  • ax+' - 類似 'a+',但如果路徑存在則會失敗

示例

創建一個 txt 文件:test.txt 在 D :\>yiibai_worksp\nodejs,內容如下:

Yiibai.Com

創建一個js文件名爲test.js 在D:\>yiibai_worksp\nodejs 目錄中。

File: test.js

var fs = require("fs");
var buffer = new Buffer(1024);

//Example: Opening File
function openFile(){
console.log("\nOpen file");
fs.open('test.txt', 'r+', function(err,fd) {
if (err) console.log(err.stack);
console.log("File opened");
});
}

//Example: Getting File Info
function getStats(){
console.log("\nGetting File Info");
fs.stat('test.txt', function (err, stats) {
if (err) console.log(err.stack);
console.log(stats);
console.log("isFile ? "+stats.isFile());
console.log("isDirectory ? "+stats.isDirectory());
});
}

//Example: Writing File
function writeFile(){
console.log("\nWrite file");
fs.open('test1.txt', 'w+', function(err,fd) {
var data = "Yiibai.com - Simply Easy Learning!";
buffer.write(data);

  fs.write(fd, buffer,0,data.length,0,function(err, bytes){
     if (err) console.log(err.stack);
     console.log(bytes + " written!");         
  });    

});
}

//Example: Read File
function readFile(){
console.log("\nRead file");
fs.open('test1.txt', 'r+', function(err,fd) {
if (err) console.log(err.stack);
fs.read(fd, buffer,0,buffer.length,0,function(err, bytes){
if (err) console.log(err.stack);
console.log(bytes + " read!");
if(bytes > 0){
console.log(buffer.slice(0,bytes).toString());
}
});
});
}

function closeFile(){
console.log("\nClose file");
fs.open('test.txt', 'r+', function(err,fd) {
if (err) console.log(err.stack);
fs.close(fd,function(){
if (err) console.log(err.stack);
console.log("File closed!");
});
});
}

function deleteFile(){
console.log("\nDelete file");
fs.open('test1.txt', 'r+', function(err,fd) {
fs.unlink('test1.txt', function(err) {
if (err) console.log(err.stack);
console.log("File deleted!");
});
});
}

function truncateFile(){
console.log("\nTruncate file");
fs.open('test.txt', 'r+', function(err,fd) {
fs.ftruncate(fd, function(err) {
if (err) console.log(err.stack);
console.log("File truncated!");
});
});
}

function createDirectory(){
console.log("\nCreate Directory");
fs.mkdir('test',function(err){
if(!err){
console.log("Directory created!");
}
if(err && err.code === 'EEXIST'){
console.log("Directory exists!");
} else if (err) {
console.log(err.stack);
}
});
}

function removeDirectory(){
console.log("\nRemove Directory");
fs.rmdir('test',function(err){
if(!err){
console.log("Directory removed!");
}
if (err) {
console.log("Directory do not exist!");
}
});
}

function watchFile(){
fs.watch('test.txt', function (event, filename) {
console.log('event is: ' + event);
});
}

//Opening file
openFile();

//Writing File
writeFile();

//Reading File
readFile();

//Closing Files
closeFile();

//Getting file information
getStats();

//Deleting Files
deleteFile();

//Truncating Files
truncateFile();

//Creating Directories
createDirectory();

//Removing Directories
removeDirectory();

//Watching File Changes
watchFile();

現在運行 test.js 看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出:

Open file

Write file

Read file

Close file

Getting File Info

Delete file

Truncate file

Create Directory

Remove Directory
File opened
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 0,
atime: Fri Jan 01 2010 00:02:15 GMT+0530 (India Standard Time),
mtime: Sun Feb 15 2015 13:33:09 GMT+0530 (India Standard Time),
ctime: Fri Jan 01 2010 00:02:15 GMT+0530 (India Standard Time) }
isFile ? true
isDirectory ? false
Directory created!
Directory removed!
event is: rename
event is: rename
42 written!
42 read!
Yiibai.com - Simply Easy Learning!
File closed!
File deleted!
File truncated!
event is: change

Node.js - 工具模塊

在這篇文章中,我們將討論一些Node.js庫提供的工具模塊,這是非常常見的,經常使用在整個應用程序中。

Sr.No.

模塊的名稱和說明

1

Console
用於打印輸出和錯誤信息

2

Process
用於獲取當前進程的信息,提供處理相關活動的多個事件

3

OS Module
提供基本的操作系統相關的實用功能

4

Path Module
實用工具提供用於處理和轉化文件路徑

5

Net Module
提供服務器和客戶端的數據流。作爲一個網絡應用包

6

DNS Module
提供的功能做實際的DNS查找,以及使用底層操作系統的名稱解析功能

7

Domain Module
提供一種方式來處理多個不同的I/O操作爲一個組

Node.js - 控制檯

Console是一個全局對象,用於打印輸出和錯誤。目標是文件是用在同步方式,或當目標是管道終端爲異步方式。

方法

Sr. No.

方法

描述

1

console.log([data][, ...])

打印及帶有換行符到stdout,此函數可將多個參數在printf()類似的方式

2

console.info([data][, ...])

打印及帶有換行符到stdout,此函數可將多個參數在printf()類似的方式

3

console.error([data][, ...])

打印及帶有換行符到stderr,此函數可將多個參數在printf()類似的方

4

console.warn([data][, ...])

打印及帶有換行符到stderr,此函數可將多個參數在printf()類似的方式

5

console.dir(obj[, options])

使用util.inspect在obj和生成的字符串打印到stdout

6

console.time(label)

標記時間

7

console.timeEnd(label)

完成定時,記錄輸出

8

console.trace(message[, ...])

打印到stderr「Trace :',其次是格式化的消息和堆棧跟蹤到當前位置

9

console.assert(value[, message][, ...])

類似於assert.ok(),但錯誤信息被格式化爲util.format(message...)

示例

創建一個js文件名爲test.js 在目錄 D:\>yiibai_worksp\nodejs

File: test.js

var counter = 10;

console.log("Counter: %d", counter);

console.time("Getting data");
//make a database call to retrive the data
//getDataFromDataBase();
console.timeEnd('Getting data');

console.info("Program Ended!")

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出

Counter: 10
Getting data: 0ms
Program Ended!

Node.js - 進程

process 是一個全局性對象,並用於表示Node進程。

退出碼

節點正常退出時帶狀態0碼,在沒有更多的異步操作掛起時。其他退出代碼描述如下:

Code

名稱

描述

1

未捕獲致命異常

有一個未捕獲的異常,它不是由域或uncaughtException事件處理程序處理

2

未使用

通過對於Bash濫用內置保留

3

內部**的**JavaScript解析錯誤

JavaScript源代碼,在內部Node引導過程引起了解析錯誤。這是極爲罕見的,一般只是在Node本身的開發過程中才發生的。

4

內部的JavaScript評估計算失敗

JavaScript源代碼,在內部Node的引導過程未能評估計算時返回一個函數值。這是極爲罕見的,一般只是在Node本身的開發過程中發生的。

5

致命錯誤

在V8中的一個致命不可恢復的錯誤。通常情況下一個消息將被打印到stderr使用前綴致命錯誤。

6

非函數內部異常處理程序

有一個未捕獲的異常,但內部致命的異常處理函數被莫名其妙地設置爲一個非函數,並且不能被調用。

7

內部異常處理程序運行時故障

這裏是一個未捕獲的異常,並試圖處理它內部的致命的異常處理函數本身拋出一個錯誤。

8

未使用

9

無效的參數

要麼未知選項指定,或沒有值時需要提供一個值的選項。

10

內部的JavaScript運行時故障

JavaScript源代碼,在內部Node引導過程中拋出一個錯誤,當引導函數被調用。這是極爲罕見的,一般Node是在開發過程中發生的。

12

無效的調試參數

--debug和/或--debug-brk選項都設置,但不能選擇無效的端口號。

>128

信號退出

如果Node接收到一個致命信號如SIGKILL或SIGHUP,然後它的退出代碼是128加上的信號代碼的值。這是一個標準Unix,實際上由於退出代碼被定義爲7位整數,信號退出設置的高序位,包含所述信號的代碼值。

事件

Process(進程)是一個eventEmitter,並且它發出下列事件

Sr.No.

Event

描述

1

exit

發射當進程即將退出。沒有辦法來防止事件循環退出在這一點上, 並且一旦所有的退出監聽器運行完成,程序將退出。

2

beforeExit

當Node清空它的事件循環,並沒有其他事情安排此事件被髮射。通常情況下,當沒有預定的工作Node退出,但是一個監聽'beforeExit'可進行異步調用,並導致Node繼續。

3

uncaughtException

發射當異常冒泡一路回到事件循環。如果一個監聽器添加了此異常,則缺省操作(這是打印堆棧跟蹤並退出)不會發生。

4

Signal Events

發射當進程接收到信號,例如SIGINT,SIGHUP等

屬性

Process(進程)提供了許多有用的特性,以更好地控制系統的相互作用。

Sr.No.

屬性

描述

1

stdout

可寫流到標準輸出

2

stderr

可寫流到stderr

3

stdin

可寫流標準輸入

4

argv

包含命令行參數數組。第一元件將是「節點」,第二個元素是JavaScript文件的名稱。接下來元素的內容是額外的命令行參數

5

execPath

這是啓動進程的可執行文件的絕對路徑

6

execArgv

這是一組Node特定的命令行選項從可執行啓動進程

7

env

包含用戶環境的對象

8

exitCode

許多可作爲進程退出代碼優雅地退出,或者是通過process.exit()無需指定代碼退出

9

version

編譯時屬性暴露NODE_VERSION

10

versions

屬性用來暴露node及其依賴的版本字符串

11

config

對象包含JavaScript用來表示編譯當前Node可執行的配置選項能力。這是類似於「config.gypi」文件,所產生在./configure腳本運行時

12

pid

進程的PID

13

title

getter/setter設置 'ps' 所顯示

14

arch

在什麼處理器架構上運行: 'arm', 'ia32', 或 'x64'

15

platform

正在運行在什麼平臺: 'darwin', 'freebsd', 'linux', 'sunos' 或 'win32'

16

mainModule

備選的方法來檢索require.main。不同的是,如果主模塊改變在運行時,require.main仍可能指的是原來的主模塊中被要求的變化發生之前的模塊。通常它是安全假設的,這兩個指的是相同的模塊

方法

Process(進程)提供了許多有用的方法,以更好的控制系統的相互作用。

Sr.No.

方法

描述

1

abort()

這導致node發出中止。node退出並生成一個核心文件

2

chdir(directory)

改變進程的當前工作目錄,或如果失敗將引發異常

3

cwd()

返回進程的當前工作目錄

4

exit([code])

終止使用指定的代碼進程。如果省略,退出使用'成功'的代碼0

5

getgid()

獲取進程組標識,這是數值組ID,而不是組名。此函數僅適用於POSIX平臺(即非Windows,Android)。

6

setgid(id)

設置進程組的標識。 (詳看setgid(2).) 這要麼接受一個數字ID或組名字符串。如果指定了組名,則此方法阻塞在解析到一個數字ID。此函數僅適用於POSIX平臺(即非Windows,Android)。

7

getuid()

獲取進程的用戶身份。這是數字ID,而不是用戶名。此函數僅適用於POSIX平臺(即非Windows,Android)。

8

setuid(id)

設置進程的用戶的身份。(請參閱setgid(2))。這接受一個數字ID或用戶名字符串。如果指定一個用戶名,這個方法會阻塞,同時解析到一個數字ID。此函數僅適用於POSIX平臺(即非Windows,Android)。

9

getgroups()

返回帶有補充組ID的數組。POSIX離開未指定是否該有效組ID包函,而Node.js保證它始終是。此函數僅適用於POSIX平臺(即非Windows,Android)。

10

setgroups(groups)

設置輔助組標識。這是一個權限操作,這意味着需要以root或具有CAP_SETGID權限。此函數僅適用於POSIX平臺(即非Windows,Android)。

11

initgroups(user, extra_group)

讀取/etc/group文件並初始化組訪問列表,使用所有這些組的用戶是其成員。這是一個權限操作,這意味着需要以root或具有CAP_SETGID權力。此函數僅適用於POSIX平臺(即非Windows,Android)。

12

kill(pid[, signal])

發送信號給一個進程。pid是進程ID和信號描述發送信號的字符串。信號的名字就像'SIGINT'或'SIGHUP'字符串。如果省略,信號是'SIGTERM'。

13

memoryUsage()

返回描述以字節爲單位的Node進程的內存使用量的對象

14

nextTick(callback)

一旦當前事件循環轉到運行結束,調用回調函數

15

umask([mask])

設置或讀取進程的文件模式創建掩碼。子進程繼承父進程的掩碼。返回老掩碼如果掩碼參數給出,否則返回當前掩碼

16

uptime()

Node已經運行的秒數

17

hrtime()

返回當前高分辨率實時在[seconds, nanoseconds] 元組。它是相對於過去的任意時間。它是不相關的一天中的時間,因此,不會受到時鐘偏移。 主要用途是用於測量時間間隔之間的性能。

示例

創建一個js文件名爲test.js 在目錄 D:\>yiibai_worksp\nodejs

File: test.js

var util = require('util');

//printing to console
process.stdout.write("Hello World!" + "\n");

//reading passed parameter
process.argv.forEach(function(val, index, array) {
console.log(index + ': ' + val);
});

//executable path
console.log(process.execPath);

//print the current directory
console.log('Current directory: ' + process.cwd());

//print the process version
console.log('Current version: ' + process.version);

//print the memory usage
console.log(util.inspect(process.memoryUsage()));

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出:

Hello World!
0: node
1: D:\yiibai_worksp\nodejs\test.js
D:\yiibai_worksp\nodejs\node.exe
Current directory: D:\yiibai_worksp\nodejs
Current version: v0.12.7
{ rss: 16379904, heapTotal: 9751808, heapUsed: 4067896 }

Node.js - OS 模塊

os模塊用於一些基本的操作系統相關的實用功能。os模塊可以使用以下語法導入。

var os = require("os")

方法

Sr. No.

方法

描述

1

os.tmpdir()

返回臨時文件操作系統的默認目錄

2

os.endianness()

返回CPU的存儲方式。可能的值是「BE」或「LE」

3

os.hostname()

返回操作系統的主機名

4

os.type()

返回操作系統名稱

5

os.platform()

返回操作系統平臺

6

os.arch()

返回操作系統的CPU架構。可能的值是「64」,「arm」和「ia32」

7

os.release()

返回操作系統版本

8

os.uptime()

返回系統正常運行時間(秒)

9

os.loadavg()

返回包含1,5和15分鐘的負載量平均值的數組

10

os.totalmem()

返回以字節系統存儲器的總量

11

os.freemem()

返回可用系統內存量(字節)

12

os.cpus()

返回一個包含每個已安裝的CPU/核心的信息對象的數組:model, speed (in MHz),和時間(含有用在CPU/核心的毫秒數量的對象:user, nice, sys, idle, and irq).

13

os.networkInterfaces()

得到的網絡接口的列表

屬性

Sr. No.

屬性

描述

1

os.EOL

操作系統限定行尾的適當標記的常量

示例

創建一個js文件名爲test.js 在 D**:\>yiibai_worksp\nodejs**

File: test.js

var os = require("os");

//endianness
console.log('endianness : ' + os.endianness());

//type
console.log('type : ' + os.type());

//platform
console.log('platform : ' + os.platform());

//totalmem
console.log('total memory : ' + os.totalmem() + " bytes.");

//freemem
console.log('free memory : ' + os.freemem() + " bytes.");

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出:

endianness : LE
type : Windows_NT
platform : win32
total memory : 4201889792 bytes.
free memory : 1233211392 bytes.

Node.js - Path 模塊

path 模塊用於處理和轉換文件路徑。path模塊可以使用以下語法導入。

var path = require("path")

屬性

進程提供了許多有用的特性,以獲得更好的控制系統的相互作用。

Sr.No.

屬性

描述

1

path.sep

特定於平臺的文件分隔符 '\\' 或 '/'.

2

path.delimiter

特定於平臺的路徑分隔符, ; 或 ':'.

3

path.posix

提供訪問路徑上述方法,但始終在POSIX兼容的方式進行交互

4

path.win32

提供訪問路徑上述方法,但總是在Win32兼容的方式進行交互

方法

Sr. No.

方法

描述

1

path.normalize(p)

規範化字符串路徑,採用'..'和'.'部分

2

path.join([path1][, path2][, ...])

連接所有參數一起和規範生成的路徑

3

path.resolve([from ...], to)

解析到一個絕對路徑

4

path.isAbsolute(path)

確定路徑是否是一個絕對路徑。絕對路徑將始終解析到相同的位置,而不考慮工作目錄

5

path.relative(from, to)

解決相對路徑從from到to

6

path.dirname(p)

返回路徑的目錄名稱,類似於Unix的目錄名的命令。

7

path.basename(p[, ext])

返回路徑的最後部分,類似於UNIX命令基名。

8

path.extname(p)

返回路徑的擴展,從最後一個「.」結束到字符串在路徑的最後部分。如果沒有'.'在路徑最後部分或第一個字符的是「.」,那麼它返回一個空字符串。

9

path.parse(pathString)

從路徑字符串返回對象

10

path.format(pathObject)

從一個對象返回 path.parse上述相反的路徑字符串

示例

創建一個js文件名爲test.js 在 D:\>yiibai_worksp\nodejs

File: test.js

var path = require("path");

//normalization
console.log('normalization : ' + path.normalize('/test/test1//2slashes/1slash/tab/..'));

//join
console.log('joint path : ' + path.join('/test', 'test1', '2slashes/1slash', 'tab', '..'));

//resolve
console.log('resolve : ' + path.resolve('test.js'));

//extName
console.log('ext name : ' + path.extname('test.js'));

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出:

normalization : \test\test1\2slashes\1slash
joint path : \test\test1\2slashes\1slash
resolve : D:\yiibai_worksp\nodejs\test.js
ext name : .js

Node.js - Net模塊

net 模塊是用來創建服務器和客戶端。它提供了一個異步網絡包裝。 net模塊可以使用以下語法導入。

var net = require("net")

方法

Sr. No.

方法

描述

1

net.createServer([options][, connectionListener])

創建一個新的TCP服務器。connectionListener參數自動設置爲監聽器的'連接'事件

2

net.connect(options[, connectionListener])

工廠方法,它返回一個新的「net.Socket」,並連接到提供的地址和端口

3

net.createConnection(options[, connectionListener])

工廠方法,它返回一個新的「net.Socket」,並連接到提供的地址和端口

4

net.connect(port[, host][, connectListener])

創建於主機的TCP連接端口。如果省略主機,默認使用「localhost」。connectListener參數將作爲一個監聽器「連接」事件。它返回一個新的「net.Socket」工廠方法

5

net.createConnection(port[, host][, connectListener])

創建於主機的TCP連接端口。如果省略主機,默認是「localhost」。 connectListener參數將作爲一個監聽器「連接」事件。它返回一個新的「net.Socket」工廠方法

6

net.connect(path[, connectListener])

創建Unix套接字連接路徑。connectListener參數將作爲一個監聽器「連接」事件。工廠方法返回一個新的「net.Socket」

7

net.createConnection(path[, connectListener])

創建Unix套接字連接路徑,connectListener參數將作爲一個監聽器「連接」事件。工廠方法返回一個新的「net.Socket」

8

net.isIP(input)

測試輸入是否爲IP地址,返回0則是無效的字符串,返回4則是IP版本4的地址, 返回6 則是IP版本6的地址

9

net.isIPv4(input)

返回true,如果輸入的是版本4的IP地址,否則返回false

10

net.isIPv6(input)

返回true,如果輸入的是版本6的IP地址,否則返回false

Class:net.Server

此類用於創建TCP或本地服務器。

方法

Sr. No.

方法

描述

1

server.listen(port[, host][, backlog][, callback])

開始接受指定的端口和主機上的連接。如果省略主機,服務器將接受針對任何IPv4地址(INADDR_ANY)連接,端口值爲0時將分配一個隨機端口

2

server.listen(path[, callback])

啓動本地socket服務器監聽給定的路徑上的連接

3

server.listen(handle[, callback])

句柄對象可以被設置爲一個服務器或socket(下面_handle構件任何東西),或一個{fd:}對象。這將導致服務器接受指定句柄連接,但可以推測該文件描述符或句柄已被綁定到端口或域套接字。監聽文件描述符在Windows上不支持。

4

server.listen(options[, callback])

port,host和backlog選項的屬性,以及可選callback 函數,這些做一個調用 server.listen(port, [host], [backlog], [callback]) 。或者,可使用的路徑選項指定一個UNIX套接字。

5

server.close([callback])

最終關閉時結束所有連接和服務器發出一個「關閉」事件

6

server.address()

操作系統返回服務器的綁定地址,所述地址族名稱和端口。

7

server.unref()

在服務器上調用unref將允許程序退出,如果這是在事件系統中唯一的活動服務器。如果服務器已經unrefd再次調用unref將無任何作用。

8

server.ref()

與unref相反,如果它是僅存的服務器(默認行爲)調用ref在unrefd之前服務器不會讓程序退出。如果服務器refd調用再次ref不會有任何效果。

9

server.getConnections(callback)

異步獲取服務器上的併發連接數量。 當套接字被送往forks。回調函數應該用兩個參數 err和count。

事件

Sr. No.

事件

描述

1

listening

發射在服務器綁定調用server.listen後

2

connection

當一個新的連接創建時發射。Socket對象,連接對象提供給事件處理。Socket是net.Socket的一個實例。

3

close

服務器關閉時發出。需要注意的是,如果連接存在,這個事件是不會發射的,直到所有的連接都結束。

4

error

當錯誤發生時發出。 「關閉」將被直接調用此事件之後。

Class:net.Socket

這個對象是一個TCP或本地套接字的抽象。net.Socket的實例實現全雙工流接口。它們可以由用戶創建,並用作一個客戶端(使用connect()),也可以由Node創建並通過服務器的'連接'事件傳遞給用戶。

事件

net.Socket是一個eventEmitter,它發出下列事件。

Sr.No.

事件

描述

1

lookup

解析主機名之後,但在連接之前發射。不適用於Unix套接字

2

connect

當成功建立一個套接字連接時發射

3

data

當接收數據時發射。參數數據將是一個緩衝或字符串。重新編碼的數據是通過socket.setEncoding()設定的

4

end

當套接字的另一端發送一個FIN包發射

5

timeout

如果套接字超閒置時發射。這是唯一的,以通知套接字已經空閒。用戶必須手動關閉連接

6

drain

當寫緩衝區變空時發射。可用於限制上傳

7

error

當錯誤發生時發射,「關閉」事件將被直接稱爲繼此事件。

8

close

當套接字被完全關閉時發射,參數had_error是一個布爾值,指明如果套接字是由於傳輸錯誤關閉。

屬性

net.Socket提供了許多有用的特性,以更好的控制套接字的相互作用。

Sr.No.

屬性

描述

1

socket.bufferSize

此屬性表示要寫入當前緩衝的字符數

2

socket.remoteAddress

遠程IP地址的字符串表示。例如, '74.125.127.100' 或 '2001:4860:a005::68'

3

socket.remoteFamily

遠程IP系列(簇)的字符串表示。 'IPv4' 或 'IPv6'

4

socket.remotePort

遠程端口的數字表示。例如,80 或 21

5

socket.localAddress

遠程客戶端連接到本地的IP地址的字符串表示。例如,如果正在在「0.0.0.0」監聽,客戶端連接到 '192.168.1.1', 那麼它的值就是 '192.168.1.1'

6

socket.localPort

本地端口的數字表示。例如,80 或 21

7

socket.bytesRead

接收的字節數

8

socket.bytesWritten

發送的字節數

方法

Sr. No.

方法

描述

1

new net.Socket([options])

構造一個新的 Socket 對象

2

socket.connect(port[, host][, connectListener])

打開一個給定的套接字連接。如果端口和主機給出,那麼套接字就會被打開作爲TCP套接字,如果省略主機,將使用localhost。如果路徑給定,套接字就會被打開作爲一個Unix套接字到該路徑

3

socket.connect(path[, connectListener])

打開一個給定的套接字連接。如果端口和主機給出,那麼套接字就會被打開作爲TCP套接字,如果省略主機,將使用localhost。如果路徑給定,套接字就會被打開作爲一個Unix套接字到該路徑

4

socket.setEncoding([encoding])

套接字爲只讀流設置編碼

5

socket.write(data[, encoding][, callback])

發送套接字上的數據。第二個參數指定的編碼是在字符串的情況 - 它默認爲UTF8編碼。

6

socket.end([data][, encoding])

半關閉套接字,即它發送FIN包。可能服務器仍然會發送一些數據。

7

socket.destroy()

確保沒有更多的I/O活動發生在此套接字。只有在錯誤的情況下(解析錯誤)有必要。

8

socket.pause()

暫停數據讀出。即,「數據」事件將不會被髮射。有用的節流回到上載

9

socket.resume()

調用 pause() 後讀取暫停

10

socket.setTimeout(timeout[, callback])

設置套接字不活動的套接字在timeout毫秒後超時。默認 net.Socket 不會超時。

11

socket.setNoDelay([noDelay])

禁用Nagle算法。默認情況下TCP連接使用Nagle算法,它們在發送之前關閉緩存數據。noDelay設置true時每次socket.write()被調用將立即釋放掉的數據。noDelay 默認值是true.

12

socket.setKeepAlive([enable][, initialDelay])

啓用/禁用保持有效功能, 可選設置初始延遲後,第一存活探測被髮送在空閒插槽。 enable 默認值是 false.

13

socket.address()

返回綁定地址, 報告操作系統的地址系列名稱和套接字的端口。 返回一個對象有三個屬性,例如{ port: 12346, family: 'IPv4', address: '127.0.0.1' }.

14

socket.unref()

套接字上調用unref 將允許程序退出,如果這是事件系統中唯一的活動套接字。如果套接字已經unrefd再次調用unref 將不會起作用。

15

socket.ref()

與unref相反,調用ref在unrefd套接字之前不會讓程序退出,如果它是唯一剩下的socket(默認行爲)。如果套接字refd調用再次ref將沒有起任何作用。

示例

創建一個js文件名爲server.js 在 D**:\>yiibai_worksp\nodejs**

File: server.js

var net = require('net');
var server = net.createServer(function(connection) {
console.log('client connected');
connection.on('end', function() {
console.log('client disconnected');
});
connection.write('Welcome to Yiibai Yiibai!\r\n');
connection.pipe(connection);
});
server.listen(8080, function() {
console.log('server is listening');
});

現在運行server.js看到的結果:

D:\yiibai_worksp\nodejs>node server.js

驗證輸出。

server is listening

創建一個js文件名爲client.js 在 C:\>Nodejs_WorkSpace.

File: client.js

var net = require('net');
var client = net.connect({port: 8080}, function() {
console.log('connected to server!');
});
client.on('data', function(data) {
console.log(data.toString());
client.end();
});
client.on('end', function() {
console.log('disconnected from server');
});

現在啓動另一個命令行窗口,運行 client.js 看到結果:

D:\yiibai_worksp\nodejs>node client.js

驗證輸出:

connected to server!
Welcome to Yiibai Yiibai!

disconnected from server

驗證,其中server.js運行輸出在終端上如下:

server is listening
client connected
client disconnected

Node.js - DNS 模塊

dns 模塊是用來做實際的DNS查找,以及使用底層操作系統的名稱解析功能..它提供了一個異步網絡包裝。dns模塊可以使用以下語法導入。

var dns = require("dns")

方法

Sr. No.

方法

描述

1

dns.lookup(hostname[, options], callback)

解析主機名(如「google.com」)進入第一找到A(IPv4)或AAAA(IPv6)紀錄。選項可以是對象或整數。如果未提供選項,那麼IP v4和v6的地址都是有效的。如果選項是整數,那麼它必須是4或6

2

dns.lookupService(address, port, callback)

使用getnameinfo會解析給定的地址和端口成一個主機名和服務

3

dns.resolve(hostname[, rrtype], callback)

解析主機名(如「google.com」)到由rrtype指定的記錄類型的數組

4

dns.resolve4(hostname, callback)

與 dns.resolve() 相同, 但僅限於IPv4的查詢(A記錄)。地址是IPv4地址的數組(如,['74.125.79.104', '74.125.79.105', '74.125.79.106'])

5

dns.resolve6(hostname, callback)

與dns.resolve4()相同,除了IPv6的查詢(一個AAAA查詢)

6

dns.resolveMx(hostname, callback)

與dns.resolve()相同,但僅限於郵件交換查詢(MX記錄)

7

dns.resolveTxt(hostname, callback)

與 dns.resolve()相同,但僅限於文本查詢(TXT記錄)。地址是文本紀錄,以供主機的2-D數組 (如, [ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ]). 每個子陣列包含一個記錄的TXT塊。根據使用的情況,可以任意連接在一起或分別處理

8

dns.resolveSrv(hostname, callback)

與dns.resolve()相同,但僅用於服務記錄(SRV記錄)。 地址是一個SRV記錄的數組提供主機名。SRV記錄屬性包括優先級,權重,端口和名稱(e.g., [{'priority': 10, 'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...]).

9

dns.resolveSoa(hostname, callback)

與 dns.resolve() 相同, 但僅限於認證記錄查詢開始(SOA記錄)

10

dns.resolveNs(hostname, callback)

與 dns.resolve() 相同, 但只針對域名服務器記錄(NS記錄)。地址是可用於主機的名稱服務器記錄的數組 (如, ['ns1.example.com', 'ns2.example.com']).

11

dns.resolveCname(hostname, callback)

與 dns.resolve()相同, 但僅限於規範名稱記錄(CNAME記錄)。地址是的規範名稱記錄可用於主機的數組 (如, ['bar.example.com']).

12

dns.reverse(ip, callback)

Reverse resolves an ip address to an array of hostnames.

13

dns.getServers()

Returns an array of IP addresses as strings that are currently being used for resolution.

14

dns.setServers(servers)

Given an array of IP addresses as strings, set them as the servers to use for resolving.

rrtypes

以下是所使用dns.resolve()方法的有效rrtypes的列表

  • A - IPV4 地址(默認)

  • AAAA - IPV6 地址

  • MX - 郵件交換記錄

  • TXT - 文字記錄

  • SRV - SRV記錄

  • PTR - 用於逆向IP查找

  • NS - 域名服務器記錄

  • CNAME - 規範名稱記錄

  • SOA - 規範記錄的開始

錯誤代碼

每個DNS查詢可以返回下列錯誤代碼之一:

  • dns.NODATA - DNS服務器返回回答不含數據

  • dns.FORMERR - DNS服務器要求查詢是misformatted

  • dns.SERVFAIL - DNS服務器返回的一般故障

  • dns.NOTFOUND - 域名未找到

  • dns.NOTIMP - DNS服務器不執行請求操作

  • dns.REFUSED - DNS服務器拒絕查詢

  • dns.BADQUERY - 非格式化的DNS查詢

  • dns.BADNAME - 非格式化的主機名

  • dns.BADFAMILY - 不支持的地址族

  • dns.BADRESP - Misformatted DNS回覆

  • dns.CONNREFUSED - 無法聯繫DNS服務器

  • dns.TIMEOUT - 超時在聯繫DNS服務器的時候

  • dns.EOF - 文件的結尾

  • dns.FILE - 讀取文件錯誤

  • dns.NOMEM - 內存不足

  • dns.DESTRUCTION - 信道被銷燬

  • dns.BADSTR - 非法格式化字符串

  • dns.BADFLAGS - 非法標誌指定

  • dns.NONAME - 給定主機名不是數字

  • dns.BADHINTS - 非法提示標誌指定

  • dns.NOTINITIALIZED - c-ares庫初始化尚未執行

  • dns.LOADIPHLPAPI - 加載 iphlpapi.dll 錯誤

  • dns.ADDRGETNETWORKPARAMS - 找不到GetNetworkParams函數

  • dns.CANCELLED - DNS查詢取消

示例

創建一個js文件名爲test.js 在 D:\>yiibai_worksp\nodejs

File: test.js

var dns = require('dns');

dns.lookup('www.yiibai.com', function onLookup(err, address, family) {
console.log('address:', address);
dns.reverse(address, function (err, hostnames) {
if (err) {
console.log(err.stack);
}

console.log('reverse for ' + address + ': ' + JSON.stringify(hostnames));
});
});

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs> node test.js

驗證輸出:

address: 112.124.103.85
Error: getHostByAddr ENOTFOUND 112.124.103.85
at errnoException (dns.js:44:10)
at Object.onresolve [as oncomplete] (dns.js:199:19)
reverse for 112.124.103.85: undefined

Node.js - Domain模塊

domain 模塊是用於攔截未處理的錯誤。這些未處理的錯誤可以使用內部綁定或外部綁定來攔截。如果錯誤都那麼不處理,那麼Node應用會崩潰。

  • 內部綁定 - 錯誤發生執行代碼是在一個域的run方法。

  • 外部綁定 - 使用它的add方法將錯誤發生明確地加入到域。

domain(域)模塊可以使用以下語法導入。

var domain = require("domain")

域模塊的Domain類是用來提供路由錯誤以及未捕獲異常活動域對象的功能。 這是一個EventEmitter的子類。爲了處理它捕獲錯誤,監聽它的錯誤事件。它使用如下的語法創建:

var domain = require("domain");
var domain1 = domain.create();

方法

Sr. No.

方法

描述

1

domain.run(function)

運行所提供的函數在域的上下文中,隱式綁定在這種情況下創建的所有事件發射器,定時器和低級請求,這是使用域的最基本的方法

2

domain.add(emitter)

顯式地將一個發射器到域。如果由發射器事件處理程序拋出一個錯誤,或者,如果發射器發出一個錯誤事件,它會被路由到該域的錯誤事件,就如隱式綁定

3

domain.remove(emitter)

與domain.add(emitter)相反。從指定的發射器處理刪除域

4

domain.bind(callback)

返回的函數將被圍繞包裝提供回調函數。當返回的函數被調用時,被拋出的任何錯誤都將被路由到該域的錯誤事件

5

domain.intercept(callback)

此方法幾乎是domain.bind(callback)相同, 然而,除了捕獲拋出錯誤,它也將截取Error 對象發送作爲第一個參數到函數。

6

domain.enter()

輸入是一種用於運行,綁定,並攔截方法來設置活動域管道。它設置domain.active和process.domain到域,並隱式地推到域,域管理模塊域棧(詳見domain.exit()詳細信息,域名棧)。調用以進入分隔鏈開始綁定到域異步調用和I/O操作。

7

domain.exit()

exit方法退出當前域,它彈出關閉域堆棧。任何時間執行將要切換到不同鏈的異步調用的上下文中,重要的是要確保當前域退出。調用以退出分隔末尾或者中斷鏈綁定到一個域的異步調用和I/O操作。

8

domain.dispose()

一旦處理被調用,該域將不再使用回調綁定到通過運行,綁定或攔截該域。以及一個dispose事件發射

屬性

Sr.No.

屬性

描述

1

domain.members

定時器和事件發射器數組已明確添加到域

示例

創建一個js文件名爲test.js 在 D:\>yiibai_worksp\nodejs

File: test.js

var EventEmitter = require("events").EventEmitter;
var domain = require("domain");

var emitter1 = new EventEmitter();

//Create a domain
var domain1 = domain.create();

domain1.on('error', function(err){
console.log("domain1 handled this error ("+err.message+")");
});

//explicit binding
domain1.add(emitter1);

emitter1.on('error',function(err){
console.log("listener handled this error ("+err.message+")");
});

emitter1.emit('error',new Error('To be handled by listener'));

emitter1.removeAllListeners('error');

emitter1.emit('error',new Error('To be handled by domain1'));

var domain2 = domain.create();

domain2.on('error', function(err){
console.log("domain2 handled this error ("+err.message+")");
});

//implicit binding
domain2.run(function(){
var emitter2 = new EventEmitter();

emitter2.emit('error',new Error('To be handled by domain2'));
});

domain1.remove(emitter1);

emitter1.emit('error',new Error('Converted to exception. System will crash!'));

現在運行test.js看到的結果:

D:\yiibai_worksp\nodejs>node test.js

驗證輸出:

listener handled this error (To be handled by listener)
domain1 handled this error (To be handled by domain1)
domain2 handled this error (To be handled by domain2)

events.js:72
throw er; // Unhandled 'error' event
^
Error: Converted to exception. System will crash!
at Object. (C:\Nodejs_WorkSpace\test.js:42:23)
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:929:3

Node.js - Web模塊

Web服務器簡介

Web服務器是用於處理使用HTTP協議請求並返回網頁作爲響應到客戶端的軟件應用程序。 Web服務器通常提供HTML文檔並伴隨着圖片,樣式表和腳本。大多數Web服務器還支持使用腳本語言作爲服務器端腳本,或重定向到從數據庫中獲取數據的執行特定任務的應用程序服務器,執行復雜的邏輯等,Web服務器然後返回應用服務器到客戶端輸出。

Apache web服務器是最常見的一個網絡服務器。它是一個開源項目。

路徑定位過程

Web服務器映射使用URL,統一資源定位符的文件的路徑。它可以是一個本地文件系統或一個外部/內部程序。例如:

客戶端使用的瀏覽器發起一個URL請求:http://www.test-example-site.com/website/index.htm.

瀏覽器發起的一個請求是:

GET /website/index.htm HTTP /1.1

HOST www.test-example-site.com

Web服務器將追加路徑到根目錄。舉個例子:根目錄是home/www,那麼實際路徑將被轉換爲 home/www/website/index.htm.

Web網絡架構介紹

Web應用程序的使用分爲四層:

  • Client - 此層是由Web瀏覽器,移動瀏覽器或應用程序,它可以發起HTTP請求到服務器。

  • Server - 這一層包括可攔截髮出的客戶端請求,並將其傳遞到由Web服務器響應。

  • Business - 這一層由應用程序服務器組成,它通過利用Web服務器執行動態任務。這一層交互通過數據庫或某些外部程序數據層。

  • Data - 此層由數據庫或任何來源的數據。

使用Node創建Web服務器

使用http.createServer方法創建HTTP服務器。通過它一個函數帶參數請求和響應。編寫一個示例實現返回一個請求頁面。通過在8081端口上監聽。

創建一個js文件名爲server.js 在 D**:\>yiibai_worksp\nodejs**

File: server.js

//http module is required to create a web server
var http = require('http');
//fs module is required to read file from file system
var fs = require('fs');
//url module is required to parse the URL passed to server
var url = require('url');

//create the server
http.createServer(function (request, response) {
//parse the pathname containing file name
var pathname = url.parse(request.url).pathname;
//print the name of the file for which request is made.
//if url is http://localhost:8081/test.htm then
//pathname will be /test.html
console.log("Request for " + pathname + " received.");
//read the requested file content from file system
fs.readFile(pathname.substr(1), function (err, data) {
//if error occured during file read
//send a error response to client
//that web page is not found.
if (err) {
console.log(err.stack);
// HTTP Status: 404 : NOT FOUND
// Content Type: text/plain
response.writeHead(404, {'Content-Type': 'text/html'});
}else{
//Page found
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/html'});
// write the content of the file to response body
response.write(data.toString());
}
// send the response body
response.end();
});
}).listen(8081);
// console will print the message
console.log('Server running at http://127.0.0.1:8081/');

創建一個名爲 test.html 的 html 文件在 D**:\>yiibai_worksp\nodejs**

File: test.html

Sample Page Hello World!

現在運行server.js看到的結果:

D:\yiibai_worksp\nodejs>node server.js

驗證輸出。服務器已經啓動

Server running at http://127.0.0.1:8081/

發出請求到Node.js服務器

在任何瀏覽器中打開以下網址:http://127.0.0.1:8081/test.html,看看下面的結果。

驗證服務器端的輸出

Server running at http://127.0.0.1:8081/
Request for /test.html received.

使用Node創建Web客戶端

Web客戶端可以使用http模塊來創建。參見下面的例子:

創建一個名爲client.js的js文件在 D:\>yiibai_worksp\nodejs

File: client.js

//http module is required to create a web client
var http = require('http');

//options are to be used by request
var options = {
host: 'localhost',
port: '8081',
path: '/test.html'
};

//callback function is used to deal with response
var callback = function(response){
// Continuously update stream with data
var body = '';
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
// Data received completely.
console.log(body);
});
}
//make a request to the server
var req = http.request(options, callback);
req.end();

現在運行client.js在不同的終端命令行,也就是在server.js以外終端上看到的結果:

D:\yiibai_worksp\nodejs>node client.js

驗證輸出:

Sample Page Hello World!

驗證服務器端的輸出

Server running at http://127.0.0.1:8081/
Request for /test.html received.
Request for /test.html received.

Node.js - Express應用程序

Express 概述

Express JS是用於創建Node JS的Web應用程序非常流行的Web應用程序框架。它提供了一個集成的環境便於快速開發基於Node的Web應用程序。Express框架是基於連接的中間件引擎並使用Jade HTML模板框架來做HTML模板。以下是一些Express 框架的核心功能:

  • 允許設立中間件來響應HTTP請求

  • 定義了用於執行基於HTTP方法和URL不同作用的路由表

  • 允許動態渲染基於參數傳遞給模板的HTML頁面

安裝Express

首先,使用NPM安裝Express框架到全局,以便它可以使用Node終端來創建Web應用程序。

D:\yiibai_worksp\nodejs> npm install express -g

當npm完成下載,可以通過查看內容來驗證,內容在 /npm/node_modules. 或輸入以下命令:

D:\yiibai_worksp\nodejs> npm ls -g

將看到以下的輸出:

C:\Documents and Settings\Administrator\Application Data\npm
+-- express@4.11.2
+-- accepts@1.2.3
| +-- mime-types@2.0.8
| | +-- mime-db@1.6.1
| +-- negotiator@0.5.0
+-- content-disposition@0.5.0
+-- cookie@0.1.2
+-- cookie-signature@1.0.5
+-- debug@2.1.1
| +-- ms@0.6.2
+-- depd@1.0.0
+-- escape-html@1.0.1
+-- etag@1.5.1
| +-- crc@3.2.1
+-- finalhandler@0.3.3
+-- fresh@0.2.4
+-- media-typer@0.3.0
+-- merge-descriptors@0.0.2
+-- methods@1.1.1
+-- on-finished@2.2.0
| +-- ee-first@1.1.0
+-- parseurl@1.3.0
+-- path-to-regexp@0.1.3
+-- proxy-addr@1.0.6
| +-- forwarded@0.1.0
| +-- ipaddr.js@0.1.8
+-- qs@2.3.3
+-- range-parser@1.0.2
+-- send@0.11.1
| +-- destroy@1.0.3
| +-- mime@1.2.11
| +-- ms@0.7.0
+-- serve-static@1.8.1
+-- type-is@1.5.6
| +-- mime-types@2.0.8
| +-- mime-db@1.6.1
+-- utils-merge@1.0.0
+-- vary@1.0.0

Express生成器

現在使用NPM安裝express生成器。express生成器用於使用express命令創建應用程序框架。

D:\yiibai_worksp\nodejs> npm install express-generator -g

將看到以下的輸出:

D:\yiibai_worksp\nodejs>npm install express-generator -g
C:\Users\Administrator\AppData\Roaming\npm\express -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\express-generator\bin\express[email protected] C:\Users\Administrator\AppData\Roaming\npm\node_modules
\express-generator
+-- sorted-object@1.0.0
+-- commander@2.7.1
+-- mkdirp@0.5.1 (minimist@0.0.8)

Hello world 示例

現在使用下面的命令創建一個示例應用程序 firstApplication:

D:\yiibai_worksp\nodejs> express firstApplication

將看到以下的輸出:

create : firstApplication
create : firstApplication/package.json
create : firstApplication/app.js
create : firstApplication/public
create : firstApplication/public/javascripts
create : firstApplication/public/images
create : firstApplication/public/stylesheets
create : firstApplication/public/stylesheets/style.css
create : firstApplication/routes
create : firstApplication/routes/index.js
create : firstApplication/routes/users.js
create : firstApplication/views
create : firstApplication/views/index.jade
create : firstApplication/views/layout.jade
create : firstApplication/views/error.jade
create : firstApplication/bin
create : firstApplication/bin/www

install dependencies:
$ cd firstApplication && npm install

run the app:
$ DEBUG=firstApplication:* ./bin/www

進入 firstApplication 文件夾並使用下面的命令來安裝 firstApplication 的依賴關係:

D:\yiibai_worksp\nodejs\firstApplication> npm install

將看到以下的輸出:

debug@2.1.2 node_modules\debug
+-- ms@0.7.0

cookie-parser@1.3.4 node_modules\cookie-parser
+-- cookie-signature@1.0.6
+-- cookie@0.1.2

morgan@1.5.1 node_modules\morgan
+-- basic-auth@1.0.0
+-- depd@1.0.0
+-- on-finished@2.2.0 (ee-first@1.1.0)

serve-favicon@2.2.0 node_modules\serve-favicon
+-- ms@0.7.0
+-- fresh@0.2.4
+-- parseurl@1.3.0
+-- etag@1.5.1 (crc@3.2.1)

jade@1.9.2 node_modules\jade
+-- character-parser@1.2.1
+-- void-elements@2.0.1
+-- commander@2.6.0
+-- mkdirp@0.5.0 (minimist@0.0.8)
+-- transformers@2.1.0 (promise@2.0.0, css@1.0.8, uglify-js@2.2.5)
+-- with@4.0.1 (acorn-globals@1.0.2, acorn@0.11.0)
+-- constantinople@3.0.1 (acorn-globals@1.0.2)

express@4.12.2 node_modules\express
+-- merge-descriptors@1.0.0
+-- cookie-signature@1.0.6
+-- methods@1.1.1
+-- cookie@0.1.2
+-- fresh@0.2.4
+-- utils-merge@1.0.0
+-- range-parser@1.0.2
+-- escape-html@1.0.1
+-- parseurl@1.3.0
+-- vary@1.0.0
+-- content-type@1.0.1
+-- finalhandler@0.3.3
+-- serve-static@1.9.1
+-- content-disposition@0.5.0
+-- path-to-regexp@0.1.3
+-- depd@1.0.0
+-- qs@2.3.3
+-- on-finished@2.2.0 (ee-first@1.1.0)
+-- etag@1.5.1 (crc@3.2.1)
+-- proxy-addr@1.0.6 (forwarded@0.1.0, ipaddr.js@0.1.8)
+-- send@0.12.1 (destroy@1.0.3, ms@0.7.0, mime@1.3.4)
+-- accepts@1.2.4 (negotiator@0.5.1, mime-types@2.0.9)
+-- type-is@1.6.0 (media-typer@0.3.0, mime-types@2.0.9)

body-parser@1.12.0 node_modules\body-parser
+-- content-type@1.0.1
+-- bytes@1.0.0
+-- raw-body@1.3.3
+-- depd@1.0.0
+-- qs@2.3.3
+-- iconv-lite@0.4.7
+-- on-finished@2.2.0 (ee-first@1.1.0)
+-- type-is@1.6.0 (media-typer@0.3.0, mime-types@2.0.9)

在這裏,express生成器創建了一個完整的應用程序結構,可以驗證在 firstApplication 文件夾中(Nodejs_WorkSpace文件夾下面)裏創建的文件夾/文件:

.
+-- app.js
+-- bin
| +-- www
+-- package.json
+-- public
| +-- images
| +-- javascripts
| +-- stylesheets
| +-- style.css
+-- routes
| +-- index.js
| +-- users.js
+-- views
+-- error.jade
+-- index.jade
+-- layout.jade

  • package.json 是應用程序描述符文件包含在依賴項列表中,應用程序使用 Node 的其他屬性

  • app.js 包含了服務器的初始化代碼

  • bin是用於存儲在生產模式下的應用程序

  • public用於存儲圖像,樣式表和JavaScript文件

  • routes 包含路由處理程序

  • views 包含HTML模板來生成Web應用各種視圖

第一個應用程序

app.js 是基於 express 的應用核心引擎。讓我們更新默認app.js包括端口信息,並使用它來創建一個服務器。添加以下行到app.js :

//set the server port
app.set('port', process.env.PORT || 3000);

//create the server
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});

更新 app.js

以下是app.js文件的全部內容

更新 app.js 文件的內容在 D**:\>yiibai_worksp\nodejs\firstApplication**.

File: app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var http = require('http');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('port', process.env.PORT || 8891);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});

http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});

module.exports = app;

現在運行app.js看到的結果:

D:\yiibai_worksp\firstApplication>node app

驗證輸出,服務器已經啓動

Express server listening on port 8891

發出一個請求到firstApplication

在瀏覽器打開網址:http://localhost:8891/,看看下面的結果:

再次在瀏覽器打開網址:http://localhost:8891/users,看看下面的結果:

基本的路由

在app.js下面的代碼綁定兩個Route處理。

var routes = require('./routes/index');
var users = require('./routes/users');
...
app.use('/', routes);
app.use('/users', users);

  • routes - 路由(index.js), 路由處理程序處理所有請求,主頁發出通過 localhost:8891

  • users - users (users.js), 路由處理來處理所有發出的請求 /users 通過 localhost:3000/users

以下是對應折代碼:D**:\>yiibai_worksp\nodejs\firstApplication\routes\index.js**是由express生成器創建。

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});

module.exports = router;

當Node服務器接收到一個主頁的請求,express路由器渲染索引頁是使用模板index.jade同時傳遞參數title的值爲'Express'。以下是模板代碼內容:D:\>yiibai_worksp\nodejs\firstApplication\views\index.jade

extends layout

block content
h1= title
p Welcome to #{title}

Node.js - 加強第一個應用程序

概述

在這篇文章中,我們將加強Express第一個應用程序,創建 Express JS 應用程序:

  • 顯示所有用戶的列表

  • 顯示一個特定的用戶的細節

  • 添加新的用戶的詳細信息

第1步:創建一個基於JSON數據庫

首先,讓我們創建一個用戶示例JSON基礎數據庫。

創建一個名爲 user.json 在一個 JSON 文件於 D**:\>yiibai_worksp\nodejs\firstApplication**

File: user.json

{
"user1" : {
"name" : "mahesh",
"password" : "password1",
"profession" : "teacher"
},
"user2" : {
"name" : "suresh",
"password" : "password2",
"profession" : "librarian"
},
"user3" : {
"name" : "newuser",
"password" : "password3",
"profession" : "clerk"
}
}

第2步:創建特定的用戶Jade視圖

在創建一個 user 目錄在 D:\>yiibai_worksp\node\firstApplication\views 如下視圖:index.jade - 查看顯示所有用戶的列表。

  • new.jade - 視圖顯示一個表單來添加一個新用戶。

  • profile.jade - 查看顯示的用戶的細節

創建一個index.jade在 D**:\>yiibai_worksp\nodejs\firstApplication\views\users**.

File: index.jade

h1 Users

p
a(href="/users/new/") Create new user
ul
- for (var username in users) {
li
a(href="/users/" + encodeURIComponent(username))= users[username].name
- };

創建一個文件 new.jade 在 D:\>yiibai_worksp\nodejs\firstApplication\views\users.

File: new.jade

h1 New User

form(method="POST" action="/Users/addUser")
P
label(for="name") Name

    input#name(name="name")
P 
    label(for\="password") Password

    input#name(name="password")
P 
    label(for\="profession") Profession

    input#name(name="profession")
P
    input(type\="submit", value\="Create")

創建一個文件 profile.jade 在 D**:\>yiibai_worksp\nodejs\firstApplication\views\users**.

File: profile.jade

h1 Name: #{user.name}

h2 Profession: #{user.profession}

第3步:更新用戶路由處理 users.js

更新文件 users.js 在 D:\>yiibai_worksp\nodejs\firstApplication\routes.

File: users.js

var express = require('express');
var router = express.Router();

var users = require('../users.json');
/* GET users listing. */
router.get('/', function(req, res) {
res.render('users/index', { title: 'Users',users:users });
});

/* Get form to add a new user*/
router.get('/new', function(req, res) {
res.render('users/new', { title: 'New User'});
});

/* Get detail of a new user */
router.get('/:name', function(req, res, next) {
var user = users[req.params.name]
if(user){
res.render('users/profile', { title: 'User Profile', user:user});
}else{
next();
}
});

/* post the form to add new user */
router.post('/addUser', function(req, res, next) {
if(users[req.body.name]){
res.send('Conflict', 409);
}else{
users[req.body.name] = req.body;
res.redirect('/users/');
}
});

module.exports = router;

現在運行app.js看到的結果:

D:\yiibai_worksp\nodejs\firstApplication>node app

驗證輸出,服務器已經啓動

Express server listening on port 3000

發出請求到firstApplication得到所有用戶的列表。在瀏覽器打開網址:http://localhost:8891/users,看看下面的結果。

點擊創建新的用戶鏈接看到表單。

提交表單並查看更新列表。

點擊查看用戶的詳細。

可以檢查服務器狀態如下:

D:\yiibai_worksp\nodejs\firstApplication>node app
Express server listening on port 3000
GET /users/ 200 809.161 ms - 201
GET /users/new/ 304 101.627 ms - -
GET /users/new/ 304 33.496 ms - -
POST /Users/addUser 302 56.206 ms - 70
GET /users/ 200 43.548 ms - 245
GET /users/naresh 200 12.313 ms - 47

Node.js - Restful API

什麼是REST架構?

REST表示代表狀態傳輸。REST是基於Web標準的體系結構並使用HTTP協議。它圍繞着資源,其中每一個組件是資源,資源是由一個共同的接口使用HTTP的標準方法獲得。REST首先是由Roy Fielding在2000年推出。

在REST架構中,REST服務器只是提供獲取資源,REST客戶端訪問和修改的資源。這裏每個資源由URI標識的/全局ID。REST使用不同方式表示資源,如文本,JSON,XML。 JSON是最流行的一種。

HTTP 方法

以下四個HTTP方法通常用在基於的REST架構。

  • GET - 提供資源的只讀訪問

  • PUT - 用於創建一個新的資源

  • DELETE - 用於刪除資源

  • POST - 用於更新現有的一個資源或創建新的資源

RESTful Web服務介紹

Web服務是用於交換應用程序或系統之間的數據開放的協議和標準的集合。寫在各種編程語言的軟件應用, 並在各種平臺上運行可以使用Web服務以類似的進程間通信的方式在一臺計算機上,通過計算機網絡交換數據,如互聯網。這種互操作性(如Java和Python,或Windows和Linux應用程序之間),是由於使用了開放標準。

基於REST架構的Web服務稱爲RESTful Web服務。這些Web服務使用HTTP方法來實現REST架構的概念。RESTful Web服務通常定義的URI,統一資源標識符的服務,提供資源的表示,如JSON,並設置HTTP方法。

爲一個庫創建RESTful

現在,我們將加強express示例應用程序,以下創建一個Web服務來用戶管理:

Sr. No.

URI

HTTP 方法

POST body

結果

1

/users/

GET

empty

顯示所有用戶的列表

2

/users/addUser

POST

JSON String

添加新的用戶的詳細信息

3

/users/:id

GET

empty

用戶的查看詳細

獲取所有用戶信息

首先,讓我們更新用戶的樣本基於JSON的數據庫。

更新JSON文件名爲user.json在 D:\>yiibai_worksp\nodejs\firstApplication.

File: user.json

{
"user1" : {
"name" : "mahesh",
"password" : "password1",
"profession" : "teacher",
"id": 1
},
"user2" : {
"name" : "suresh",
"password" : "password2",
"profession" : "librarian",
"id": 2
},
"user3" : {
"name" : "ramesh",
"password" : "password3",
"profession" : "clerk",
"id": 3
}
}

當客戶端發送GET請求/用戶,服務器應該發送一個包含所有用戶的響應。更新用戶的路由處理,users.js

更新 users.js 在 D:\>yiibai_worksp\nodejs\firstApplication\routes.

File: users.js

/* GET users listing. */
router.get('/', function(req, res) {
res.send({ title: 'Users',users:users });
});

添加新的用戶的詳細信息

當客戶端發送一個POST請求 /users/addUser 包含JSON字符串,服務器應該發送一個響應聲明狀態。更新用戶的路由處理users.js

更新 users.js 在 D:\>Nodejs_WorkSpace\firstApplication\routes.

File: users.js

/*add a user*/
router.post('/addUser', function(req, res, next) {
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
var json = JSON.parse(body);
users["user"+json.id] = body;
res.send({ Message: 'User Added'});
});
});

顯示新用戶的詳細信息

當客戶端發送GET請求到/users並帶有id,服務器響應返回包含該用戶的詳細信息。更新用戶的路由處理程序:users.js

更新 users.js 在 D:\>yiibai_worksp\nodejs\firstApplication\routes,如下:

File: users.js

router.get('/:id', function(req, res, next) {
var user = users["user" + req.params.id]
if(user){
res.send({ title: 'User Profile', user:user});
}else{
res.send({ Message: 'User not present'});
}
});

完整的users.js 代碼

File: users.js

var express = require('express');
var router = express.Router();

var users = require('../users.json');
/* GET users listing. */
router.get('/', function(req, res) {
res.send({ title: 'Users',users:users });
});

router.get('/:id', function(req, res, next) {
console.log(req.params)
var user = users["user" + req.params.id]
if(user){
res.send({ title: 'User Profile', user:user});
}else{
res.send({ Message: 'User not present'});
}
});

router.post('/addUser', function(req, res, next) {
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
var json = JSON.parse(body);
users["user"+json.id] = body;
res.send({ Message: 'User Added'});
});
});

module.exports = router;

輸出

我們使用一個Chrome瀏覽器的掃插件:Postman, 來測試我們編寫的 webservices,安裝Postman需要到以下網址下載(可能需要翻牆):https://chrome.google.com/webstore/detail/postman-interceptor/aicmkgpgakddgnaphhhpliifpcfhicfo 安裝好這個插件後,打開後顯示如下圖:

Node.js快速入門

現在運行app.js看到的結果:

D:\yiibai_worksp\nodejs\firstApplication> node app

驗證輸出。服務器已經啓動

Express server listening on port 8891

提出一個請求到firstApplication獲取所有用戶的信息列表。把 http://localhost:8891/users 到POSTMAN 地址欄中,並使用GET請求,看到下面的結果。

Node.js快速入門

發出一個請求到 firstApplication 以添加一個新用戶。把 http://localhost:8891/users/addUser 放入到POSTMAN中並使用POST方式提交,看看下面的結果。

添加JSON數據格式,並選擇POST方法。

{"name":"rakesh","password":"password4","profession":"teacher","id":5}

Node.js快速入門

點右側的「Send」按鈕,返回結果如下:

Node.js快速入門

發出一個請求 firstApplication 獲得用戶。把 http://localhost:8891/users/1 在POSTMAN中找打開並用GET請求,看看下面的結果。
Node.js快速入門

Node.js - 縮放應用

Node是在單線程模式下運行,它使用事件驅動的模式來處理併發。它還有助於創建子進程來利用並行處理在多核CPU的系統。

子進程始終有三個流child.stdin,child.stdout和child.stderr ,可以與父進程共享標準輸入輸出流。它們能夠通過一個單獨的流對象管道輸送。

主要有三種方法來創建子進程。

  • exec - child_process.exec方法在shell/控制檯運行一個命令並緩衝輸出。

  • spawn - child_process.spawn由給定的命令啓動一個新的進程

  • fork - child_process.fork方法是spawn() 創建Node進程的一個特例。

exec() 方法

child_process.exec方法在shell運行一個命令並緩衝輸出。它簽名如下:

child_process.exec(command[, options], callback)

  • command String要運行的命令,用空格分隔參數

  • options 對象

    • cwd 當前工作目錄子進程的字符串

    • env 對象環境鍵值對

    • encoding 字符串(缺省:'utf8'')

    • shell 字符串Shell來執行(默認命令:在UNIX上在「/bin/sh」,在Windows爲cmd.exe「,在shell中應該知道在Windows或UNIX/S/C-c開關。在Windows中,命令行解析應與cmd.exe兼容)

    • timeout 數字(默認值: 0)

    • maxBuffer 數字(默認值: 200*1024)

    • killSignal 字符串(默認值: 'SIGTERM')

    • uid 數字設置進程的用戶身份

    • gid 數字設置進程的組標識

  • callback 當進程終止函數調用輸出

    • error Error

    • stdout Buffer

    • stderr Buffer

  • **Return:**ChildProcess對象

exec() 返回一個緩衝器的最大尺寸,並等待該進程結束,並試圖在一次返回所有緩衝的數據

示例

創建兩個JS文件名爲worker.js和master.js在 D:\>yiibai_worksp\nodejs

File: worker.js

console.log("Child Process "+ process.argv[2] +" executed." );

File: master.js

const fs = require('fs');
const child_process = require('child_process');

for(var i=0; i<3; i++) {
var workerProcess = child_process.exec('node worker.js '+i,
function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: '+error.code);
console.log('Signal received: '+error.signal);
}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});

  workerProcess.on('exit', function (code) {
  console.log('Child process exited with exit code '+code);

});
}

現在運行master.js看到的結果:

D:\yiibai_worksp\nodejs> node master.js

驗證輸出。服務器已經啓動

Child process exited with exit code 0
stdout: Child Process 1 executed.

stderr:
Child process exited with exit code 0
stdout: Child Process 0 executed.

stderr:
Child process exited with exit code 0
stdout: Child Process 2 executed.

spawn() 方法

child_process.spawn方法由給定的命令啓動一個新的進程。它具有以下簽名

child_process.spawn(command[, args][, options])

  • command 字符串 - 要運行的命令

  • args 字符串參數數組列表

  • options 對象

    • cwd 當前工作目錄子進程的字符串

    • env 對象環境鍵值對

    • stdio 數組|子字符串的標準輸入輸出配置

    • customFds Array不推薦文件描述符由子進程使用標準輸入輸出

    • detached boolean值 - 子進程是一個進程組頭進程

    • uid 數字設置進程的用戶身份

    • gid Number設置進程的組標識

  • Return: ChildProcess對象

spawn() 返回流(標準輸出與標準錯誤),並會使用當該過程返回大數據量。spawn()即開始接收到響應進程開始執行。

示例

創建兩個JS文件名爲worker.js和master.js在  D:\>yiibai_worksp\nodejs

File: worker.js

console.log("Child Process "+ process.argv[2] +" executed." );

File: master.js

const fs = require('fs');
const child_process = require('child_process');

for(var i=0; i<3; i++) {
var workerProcess = child_process.spawn('node', ['worker.js', i]);

workerProcess.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});

workerProcess.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});

workerProcess.on('close', function (code) {
console.log('child process exited with code ' + code);
});
}

現在運行master.js看到的結果:

D:\yiibai_worksp\nodejs> node master.js

驗證輸出。服務器已經啓動

stdout: Child Process 0 executed.

child process exited with code 0
stdout: Child Process 2 executed.

child process exited with code 0
stdout: Child Process 1 executed.

child process exited with code 0

fork 方法

child_process.fork方法是spawn() 的一個特例用來創建Node進程。它具有以下簽名

child_process.fork(modulePath[, args][, options])

  • modulePath 字符串- 模塊運行所在的子進程

  • args 字符串參數數組列表

  • options 對象

    • cwd 當前工作目錄子進程的字符串

    • env 對象環境鍵值對

    • execPath 字符串可執行用於創建子進程

    • execArgv 傳遞給程序的可執行字符串參數數組列表(默認值:process.execArgv)

    • silent Boolean如果爲true,stdin, stdout, 和 stderr 的標準錯誤將被輸送到父進程,否則它們將繼承自父,詳情參見「管道」和「繼承」 選項spawn()的標準輸入輸出(默認爲false)

    • uid 數字設置進程的用戶身份

    • gid 數字設置進程的組標識

  • Return: ChildProcess 對象

fork返回對象有內置的通信信道,除了具有正常的ChildProcess實例的所有方法。

示例

創建兩個JS文件名爲 worker.js 和 master.js 在 D:\>yiibai_worksp\nodejs

File: worker.js

console.log("Child Process "+ process.argv[2] +" executed." );

File: master.js

const fs = require('fs');
const child_process = require('child_process');

for(var i=0; i<3; i++) {
var worker_process = child_process.fork("worker.js", [i]);

worker_process.on('close', function (code) {
console.log('child process exited with code ' + code);
});
}

現在運行master.js看到的結果:

D:\yiibai_worksp> node master.js

驗證輸出。服務器已經啓動

Child Process 0 executed.
Child Process 1 executed.
Child Process 2 executed.
child process exited with code 0
child process exited with code 0
child process exited with code 0