Node.js快速入門

1、概述

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.html

Node.js是一個基於Google Chrome的V8引擎的JavaScript運行環境,它容許使用JavaScript語言編寫服務器端代碼。Node.js具備事件驅動和I/O非阻塞兩大特色,輕量而高效。node

官網地址webpack

2、安裝與運行

從官網下載最新版本的Node.js,直接安裝。安裝時選擇所有組件,並添加到環境變量Path中。web

運行命令:node -v查看是否安裝成功。算法

運行命令:node進入到node.js的交互環境,能夠輸入任意JavaScript語句,並查看運行結果。數據庫

運行命令:node <*.js>直接執行js文件裏的內容。express

運行命令:node --use_strict <*.js>爲js文件開啓嚴格模式。npm

安裝Node.js的時候,會自動安裝包管理工具npm。後端

運行命令:npm -v查看npm的版本。api

命令行模式會一次性執行js文件,中間沒有交互;交互模式則是每一行單獨執行,能夠進行交互。

若是不想使用集成的IDE,可使用VS Code編輯器進行Node.js的開發和調試。具體操做和配置能夠參照VS Code的官網教程。

VS Code官網地址

Node.js Applications with VS Code

3、模塊

在Node.js環境中,一個js文件就稱之爲一個模塊。使用模塊提升了代碼的可維護性以及可重用性,還避免了函數名和變量名衝突。

當在模塊中定義一個對象(對象、函數、數組等)時,能夠輸出這個對象以供其餘模塊使用:

module.exports = object_name;

其餘模塊要想使用這個對象,能夠在模塊中引入該對象:

var variable_name = require('/path/to/the/module/module_name');

Tips:若是不指定路徑,Node會按照內置模塊、全局模塊、當前模塊的順序進行查找。

一、基本模塊

在瀏覽器中,JavaScript有一個全局對象window;而在Node.js環境中,也有一個全局對象global。因爲JavaScript代碼既能在瀏覽器執行,也能在Node環境下執行,能夠經過全局對象名稱來判斷JavaScript代碼是在哪一個環境下執行的。

process也是Node.js提供的一個對象,表示當前Node.js進程,進程自己的事件由process來處理。

二、經常使用內置模塊

fs模塊是文件系統模塊,負責文件的讀寫操做,提供了同步和異步兩種方法。大部分做爲服務端的代碼,必須使用異步代碼。可是在服務器啓動時讀取配置文件,或結束時寫入狀態等操做,由於這些代碼只執行一次,因此可使用同步方法。

讀文本文件:

var fs = require('fs');
fs.readFile('input.txt', 'utf-8', function (err, data) {
  if (err) {
    console.log(err);
  } else {
    console.log(data);
  }
});

其中,readFile函數的第一個參數是文件名,第二個參數是文件編碼,第三個參數是一個回調函數。回調函數的第一個參數表明錯誤信息,第二個參數表明返回結果。

讀二進制文件:

var fs = require('fs');
fs.readFile('input.png', function (err, data) {
  if (err) {
    console.log(err);
  } else {
    console.log(data);
    console.log(data.length + ' bytes');
  }
});

其中,不須要文件編碼,而且回調函數的data參數將返回一個Buffer對象。Buffer對象是一個包含零個或任意個字節的數組。

寫文件:

var fs = require('fs');
var data = 'Hello world';
fs.writeFile('output.txt', data, function (err) {
  if (err) {
    console.log(err);
  } else {
    console.log('success');
  }
});

其中,writeFile函數的第一個參數是文件名,第二個參數是要寫入的數據,第三個參數是回調函數。

讀取文件的相關信息:

fs.stat('input.txt', function (err, stat) {
  ...
});

stream是一個只能在服務端使用的模塊,用來支持流數據結構,流中的數據是有序的。流是一個對象,使用時只需關注流的事件便可。data事件表示流的數據能夠讀取,end事件表示流沒有數據能夠讀取,error事件表示出現錯誤。

讀文件:

var fs = require('fs');
var rs = fs.createReadStream('input.txt', 'utf-8');
rs.on('data', function (chunk) {
  console.log('DATA:');
  console.log(chunk);
});
rs.on('end', function () {
  console.log('END');
});
rs.on('error', function (err) {
  console.log('ERROR: ' + err);
});

寫文件:

var fs = require('fs');
var ws1 = fs.createWriteStream('output1.txt', 'utf-8');
ws1.write('使用Stream寫入文本數據...\n');
ws1.write('END.');
ws1.end();

var ws2 = fs.createWriteStream('output2.txt');
ws2.write(new Buffer('使用Stream寫入二進制數據...\n', 'utf-8'));
ws2.write(new Buffer('END.', 'utf-8'));
ws2.end();

可使用管道操做pipe將讀取流和寫入流串聯起來:

var fs = require('fs');
var rs = fs.createReadStream('input.txt');
var ws = fs.createWriteStream('output.txt');
rs.pipe(ws);

默認狀況下,當讀取流的數據讀取完畢,會觸發end事件,並自動關閉寫入流。若是不想關閉,須要傳遞額外的參數。

readable.pipe(writable, { end: false });

http模塊是web應用最經常使用的一個模塊,提供了request和response對象。request對象封裝HTTP請求,調用request對象的屬性和方法,能夠獲取HTTP請求的全部信息;response對象封裝HTTP響應,調用response對象的方法,能夠把HTTP響應返回給瀏覽器。

var http = require('http');
var server = http.createServer(function (request, response) {
  // 獲取HTTP請求的method和url
  console.log(request.method + ':' + request.url);
  // 將HTTP響應的內容寫入response
  response.writeHead(200, {'Content-Type': 'text/html'});
  response.end('<h1>Hello world!</h1>');
});
// 監聽8080端口
server.listen(8080);

url模塊能夠用來將URL字符串解析成一個Url對象,從而獲取想要的信息。

var url = require('url');
console.log(url.parse('http://user:pass@host.com:8080/path/to/file?query=string#hash'));

path模塊能夠用來處理本地文件目錄。

var path = require('path');
// 解析當前目錄
var workDir = path.resolve('.');
// 組合完整的文件路徑
var filePath = path.join(workDir, 'pub', 'index.html');

crypto模塊提供通用的加密和哈希算法。

MD5哈希算法用來給任意數據一個簽名,一般用一個十六進制字符串表示:

const crypto = require('crypto');
const hash = crypto.createHash('md5');
hash.update('Hello, world!');
console.log(hash.digest('hex'));

Hmac哈希算法能夠利用MD5等算法,另外還須要一個密鑰:

const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('Hello, world!');
console.log(hmac.digest('hex'));

AES是一種經常使用的對稱加密算法,加密與解密使用同一個密鑰。crypto模塊提供了AES支持,但須要自行封裝。DiffieHellman算法是一種密鑰交換協議,可讓雙方自行協商一個密鑰。crypto模塊還能夠處理數字證書。

4、Web開發

使用Node.js開發Web服務器端,有幾點好處:

  • 先後端統一使用JavaScript,不須要切換語言
  • 異步處理大大提升了運行速度

針對Node.js,出現了不少後端相關的Web框架、ORM框架、模板引擎、測試框架、構建工具等。

一、Web框架Express/koa

Express是第一代最流行的Web服務端框架,它對Node.js的http進行了封裝。雖然Express的API很是簡單,可是因爲是基於ES5,要實現異步,只能使用回調。若是異步嵌套層次過多,代碼很難理解。

var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('Hello World!');
});
app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

koa1基於ES6,使用generator實現異步。雖然使用generator在寫法上比回調簡單,但其本意並非用於異步。真正設計用來實現異步的是Promise,但Promise的寫法過於複雜。

var koa = require('koa');
var app = koa();
app.use('/test', function *() {
  yield doReadFile1();
  var data = yield doReadFile2();
  this.body = data;
});
app.listen(3000);

koa2基於ES7,使用Promise和關鍵字async配合實現異步,同時兼容generator的寫法。

app.use(async (ctx, next) => {
  await next();
  var data = await doReadFile();
  ctx.response.type = 'text/plain';
  ctx.response.body = data;
});

二、ORM框架Sequelize

ORM技術是將關係型數據庫的表結構映射到對象上,Sequelize返回Promise對象,能夠更好地進行異步處理。

ES6:

Pet.findAll()
 .then(function (pets) {
   for (let pet in pets) {
     console.log(`${pet.id}: ${pet.name}`);
   }
 }).catch(function (err) {
   // error
 });

ES7:

(async () => {
  var pets = await Pet.findAll();
})();

要想使用Sequelize操做數據庫,首先須要建立一個Sequelize實例。而後定義數據模型Model,使用Sequelize映射數據庫表。這樣就能夠調用實例的相應方法來對數據庫進行操做。

Sequelize操做數據庫的通常步驟:

  • 經過Model對象的findAll()方法獲取實例
  • 若是要更新實例,先對實例屬性進行賦值,而後調用save()方法
  • 若是要刪除實例,直接調用destroy()方法

三、模板引擎Jade/Pug

Node.js默認使用Jade做爲模板引擎(現更名爲Pug)。Jade是Node.js的一個模塊,jade文件能夠被預編譯爲.js文件,也能夠被編譯爲目標html代碼。

主頁

四、測試框架Mocha

Mocha是JavaScript的單元測試框架,既能夠在瀏覽器環境運行,也能夠在Node.js的環境運行。

特色:

  • 既能夠測試簡單的JavaScript函數,又能夠測試異步代碼
  • 既能夠自動運行全部測試,也能夠只運行特定的測試
  • 能夠支持before、after、beforeEach和afterEach來編寫初始化代碼

五、構建工具Webpack

六、WebSocket協議

WebSocket利用HTTP協議創建鏈接,在瀏覽器和服務器之間創建雙向通訊的通道,服務器能夠主動向瀏覽器發送消息,而不須要經過瀏覽器發送請求。

首先,WebSocket鏈接必須由瀏覽器發起,由於請求協議是一個標準的HTTP請求。

GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13

與普通HTTP請求的區別:

  • GET請求的地址以ws://開頭
  • 請求頭Upgrade: websocketConnection: Upgrade表示鏈接將被轉換爲WebSocket鏈接
  • Sec-WebSocket-Key用於標識這個鏈接
  • Sec-WebSocket-Version指定WebSocket的協議版本

而後,若是服務器接受請求,會返回響應:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string

其中,響應碼101表示將切換協議,切換後的協議經過Upgrade來指定。

在Node.js中,最經常使用的WebSocket模塊是ws。建立一個WebSocket的服務器實例:

const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;
const wss = new WebSocketServer({
  port: 3000
});

若是有WebSocket請求接入,wss對象能夠響應connection事件來處理這個WebSocket。對於每一個WebSocket鏈接,都要對它綁定某些事件方法來處理不一樣的事件。


參考文章:

廖雪峯:Node.js教程

相關文章
相關標籤/搜索