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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ayugioh2003.gitbook.io/front2end/front/googleyu-yong-wang-ye-yu-yan-node-js.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
