Google御用網頁語言 Node.js

Google御用網頁語言 Node.js

3 Node.js 快速入門

3.1 開使用 Node.js 程式設計

3.1.3 建立 http 伺服器

// app.js

var http = require("http");

http.createServer(function(req, res){
    res.writeHead(200, {"Content-Type": "text/html"});
    res.write("<h1>Node.js 321</h1>");
    res.end("<p>Hello World</p>");
}).listen(3000);

console.log("HTTP server is listening at port 3000");

3.2 非同步 i/o 與事件型程式設計

3.2.2 回呼函數

以非同步讀取檔案

// readfile.js

var fs = require("fs");

fs.readFile("file.txt", "utf-8", function(err, data){
    if(err){
        console.error(err);
    } else{
        console.log(data);
    }
});

console.log("end.");

同步讀取檔案

// readfilesync.js

var fs = require("fs");
var data = fs.readFileSync("file.txt", "utf-8");

console.log(data);
console.log("end.");

非同步的另一種寫法

// readfilecallback.js

function readFileCallBack(err, data){
    if(err){
        console.error(err);
    } else {
        console.log(data)
    }
}

var fs = require("fs");
fs.readFile("file.txt", "utf-8", readFileCallBack);
console.log("end.");

3.2.3 事件

Node.js 所有的非同步 io 操作在完成時都會發送一個事件到事件佇列。在開發者看來,事件由 EventEmitter 物件提供。

event 物件註冊了事件 some_event 的一個監聽器,然後透過 setTimeout 在1000毫秒以後向 event 物件發送事件 some_event,此時會呼叫 some_event 的監聽器

// event.js

var EventEmitter = require("events").EventEmitter;
var event = new EventEmitter();

event.on("some_event", function(){
    console.log("some_event occured.");
});

setTimeout(function(){
    event.emit("some_event");
}, 1000);

3.3 模組與套件

3.3.2 建立及載入模組

建立模組

// module.js

var name;

exports.setName = function(thyName){
    name = thyName;
};

exports.sayHello = function(){
    console.log("Hello " + name);
};

載入模組並使用

// getmodule.js

var myModule = require("./module");

myModule.setName("BYVoid");
myModule.sayHello();

單次載入

hello1與hello2指向同一個實例,結果會被覆蓋

// loadmodule.js

var hello1 = require("./module");
hello1.setName("BYVoid");

var hello2 = require("./module");
hello2.setName("BYVoid 2");

hello1.sayHello();

覆載 exports

原先想把物件封裝到模組,可能會這樣打

// singleobject.js

function Hello(){
    var name;

    this.setName = function (thyName){
        name = thyName;
    }

    this.sayHello = function(){
        console.log("Hello " + name);
    }
}

exports.Hello = Hello;

但這樣要用 require("./singleobject").Hello 來取得 Hello 物件,太麻煩,所以要簡化

// hello.js

function Hello(){
    var name;

    this.setName = function (thyName){
        name = thyName;
    }

    this.sayHello = function(){
        console.log("Hello " + name);
    }
}

module.exports = Hello;

之後就可以比較方便的取得hello 物件

// gethello.js

var Hello = require("./hello");

hello = new Hello();
hello.setName("BYVoid");
hello.sayHello();

3.3.3 建立套件

符合 commonJS 的標準套件應該有

  • package.json 在套件的頂層目錄下

  • 二進位檔案應該在 bin 目錄下

  • JavaScript 程式應該在 lib 目錄下

  • 文件應該在 doc目錄下

  • 單元測試應該在 test 目錄下

1.是資料夾的模組

架構

  • somepackage

    • index.js

  • getpackage.js

簡單的將資料夾封裝成模組

// somepackage/index.js

exports.hello = function(){
    console.log("Hello. ");
};

引用模組

// getpackage.js

var somePackage = require("./somepackage");

somePackage.hello();
  1. package.json

結構

  • somepackage

    • package.json

    • lib

      • interface.js (index.js)

  • getpackage.js

node.js 在呼叫套件時,會先檢查 package.json 的 main 欄位,將其視為套件的界面模組。如果 package.json 或 main 欄位不存在,會嘗試尋找 index.js 或是 index.node 的套件界面

// somepackage/interface.json
{
    "main": "./lib/interface.js"
}

符合 commonJS 欄位要有

  • name 套件的名稱

  • description 簡要說明

  • version 版本

  • keywords

  • maintainers

  • contributors

  • bugs 傳送 bug 的網址

  • licenses 許可證陣列

  • repositories 倉庫託管地址

  • dependencies 套件的相依

3.3.4 Node.js套件管理員

取得一個套件 安裝方式 npm install -g express

建立全域連結

npm link express
./node_modules/express -> /usr/local/lib/node_modules/express

套件的發布

  • `npm init,建了 package.json

  • 建立 index.js 套件界面

  • npm adduser 建立使用者(id, password, email)

  • npm whoami 測驗是否取得了帳號

  • npm publish npm unpublish

  • npm install

3.4 偵錯

命令列偵錯

node debug debug.js

4 Node.js 核心模組

常用部份

  • 全域物件

  • 常用工具

  • 事件機制

  • 檔案系統存取

  • HTTP 伺服器與用戶端

4.1 全域物件

4.1.1 全域物件與全域變數

4.1.2 process

全域變數,描述目前Node.js處理程序狀態的物件

  • process.argv 命令列參數陣列

  • process.stdout

    • process.stdout.write()

  • process.stdin

  • process.nextTick(callback)

4.1.3 console

用於向標準輸出流stdout或標準錯誤流stderr輸出字元

  • console.log() 向標準輸出流列印字元

  • console.err() 向標準錯誤流列印字元

  • console.trace() 向標準錯誤流輸出目前的呼叫堆疊

4.2 常用工具 util

util 是一個 node.js 的核心模組,提供常用函數的集合,用於彌補js 的功能過於精簡的不足

4.2.1 util.inherits

util.inherits(construcotr, superConstrucotr) 是一個實現物件間圓形繼承的函數。

4.2.2 util.inspect

util.inspect(object, [showHidden], [depth], [colors]) 是一個將任意物件轉為字串的方法,通常用於偵錯和錯誤輸出。她至少接受一個參數object,輯要轉還得物件

4.3 事件驅動 events

node.js 中最重要的模組,因為node.js 本身架構就是事件是的,而它提供了唯一的界面,所以堪稱 node.js 事件程式設計的基礎。events 模組不僅用於使用者程式與node.js下層事件迴圈的互動,還幾乎被所有的模組相依

4.3.1 事件發射器

events 模組只提供了一個物件:events.EventEmitter。EventEmitter的核心就是事件發射與事件監聽器功能的封裝。EventEmitter的每個事件由一個事件名稱和許多個參數組成,事件名稱是一個字串,通常表達一定的語義。對於每個事件,EventEmitter支援許多個事件監聽器。當事件發射時,註冊到這個事件的事件監聽器被一次呼叫,事件參數是回忽函數參數傳遞。

var events = require("events");
var emitter = new events.EventEmitter();

// 設定 someEvent 事件監聽器
emitter.on("someEvent", function(arg1, arg2){
    console.log("listener1", arg1, arg2);
});

emitter.on("someEvent", function(arg1, arg2){
    console.log("listener2", arg1, arg2);
});

// 發射 someEvent 事件
emitter.emit("someEvent", "byvoid", 1991);

4.3.2 error 事件

遇到例外的時候通常會發射error 事件。當error被發射時,EventEmitter規定如果沒有反應的監聽器,Node.js會把她當作例外,退出程式並列印呼叫堆疊。我們一般要為會發射error事件的物件設定監聽器,避免遇到錯誤後整個程式崩潰。

4.3.3 繼承EventEmitter

通常不會直接使用EventEmitter,而是在物件中繼承她。八涵fs, net, http在內的,只要是支援事件反應的核心模組都是 EventEmittere的子類別。

eof這麼做原因二。首先,具有某個實體功能的物件實現事件符合語意,事件的晶聽和發射應該是一個物件的方法。其次js的物件之至是以源行為基礎的,支援部份多重繼承,繼承EventEmitter不會打亂物件元有的繼承關係。

Last updated