> For the complete documentation index, see [llms.txt](https://ayugioh2003.gitbook.io/front2end/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ayugioh2003.gitbook.io/front2end/front/googleyu-yong-wang-ye-yu-yan-node-js.md).

# Google御用網頁語言 Node.js

## Google御用網頁語言 Node.js

### 3 Node.js 快速入門

#### 3.1 開使用 Node.js 程式設計

**3.1.3 建立 http 伺服器**

```javascript
// 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 回呼函數**

以非同步讀取檔案

```javascript
// 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.");
```

同步讀取檔案

```javascript
// readfilesync.js

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

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

非同步的另一種寫法

```javascript
// 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 的監聽器

```javascript
// 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 建立及載入模組**

> 建立模組

```javascript
// module.js

var name;

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

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

載入模組並使用

```javascript
// getmodule.js

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

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

> 單次載入

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

```javascript
// loadmodule.js

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

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

hello1.sayHello();
```

> 覆載 exports

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

```javascript
// 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 物件，太麻煩，所以要簡化

```javascript
// hello.js

function Hello(){
    var name;

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

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

module.exports = Hello;
```

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

```javascript
// 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

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

```javascript
// somepackage/index.js

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

引用模組

```javascript
// 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 的套件界面

```javascript
// 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`

建立全域連結

```bash
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 偵錯

命令列偵錯

```bash
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支援許多個事件監聽器。當事件發射時，註冊到這個事件的事件監聽器被一次呼叫，事件參數是回忽函數參數傳遞。

```javascript
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不會打亂物件元有的繼承關係。
