背景
在前端歷史演變中已經提到,Nodejs的爆發從2009年開始。Nodejs的出現,基於作者Ryan Dahl 對Web開發高性能的追求,要達到高性能,異步IO/事件驅動是基本原則。對比一些高級語言,最終選擇Javascript作爲開發語言,由於Javascript天生的事件驅動和單線程,奠定了Nodejs編寫高性能Web服務輕而易舉。
簡單瞭解Nodejs
Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境。
Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效。
Chrome V8 引擎介紹
V8 引擎是Chrome於2008年9月2日發佈開源。V8使用C++開發,相比其它的JavaScript的引擎轉換成字節碼或解釋執行,V8將其編譯成原生機器碼(IA-32, x86-64, ARM, or MIPS CPUs),並且使用瞭如內聯緩存(inline caching)等方法來提高性能。有了這些功能,JavaScript程序在V8引擎下的運行速度媲美二進制程序。
Chrome瀏覽器在Webkit渲染引擎中使用v8引擎來提高瀏覽器的渲染性能。
上圖是webkit大致結構,紅色部分是webkit的默認引擎,在谷歌系列產品中被替換爲v8引擎;
Nodejs是站在“巨人的肩膀”上進行一系列的封裝,它的高性能,離不開Chorme V8引擎。
JavaScript 運行環境
Javascript 是一個靜態腳本語言,運行時必須要藉助於引擎才能運行。
Javascript 運行環境一般分爲兩種:
- 瀏覽器運行環境 ( 通常我們寫的js代碼要在瀏覽器中才能運行)
- 非瀏覽器運行環境 (比如Nodejs,藉助於V8引擎實現運行的環境)
事件驅動
我們在Javascript中註冊個事件(回調函數)。但這個事件不是馬上執行。只有等事件被觸發的時候,纔會去執行這個事件(回調函數)。這種形式就是事件驅動。
非阻塞 I/O
阻塞:前一個程序未執行完就得一直等待。比如當你打電話問個問題時,那邊說你等等我給你查查,這時候你電話仍然是掛起的,等待等待,直到拿到結果。
非阻塞:前一個程序未執行完時可以掛起,繼續執行其他程序,等到使用時再執行。比如當你打電話過去問一個問題,然後掛電話,等那邊找到結果就打電話給你。查問題這段時間,你該幹嘛就幹嘛。
I/O: 磁盤的寫入(in)磁盤的讀取(out)。在程序執行過程中必然要進行很多I/O操作,讀寫文件、輸入輸出、請求響應等等。I/O操作時最費時,舉個例子,你要讀一個文件,整個線程都暫停下來,等待文件讀完後繼續執行。換言之,I/O操作阻塞了代碼的執行,極大地降低了程序的效率。
在Nodejs裏面單線程可以通過回調函數(事件驅動)來做異步操作,達到非阻塞I/O的效果。
安裝Nodejs
#安裝
brew install -g node
#卸載
brew uninstall nodejs
- 使用nvm安裝管理Nodejs版本
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
# or
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
# 放入環境變量
source ~/.bash_profile
# 判斷是否安裝成功
nvm list
# 安裝node
nvm install 6.14.4 # or 10.10.0, 8.9.1, etc
# 判斷node安裝成功
node -v
npm -v
Nodejs 的簡單使用
模塊化規範 CommonJs
在前端模塊化中已經對CommonJs做了介紹,並使用exports導出模塊,require引入模塊,實現了一個簡單案例。
- require:引入一個模塊
- exports: 導出模塊內容
- module: 模塊本身
使用Nodejs創建服務
// index.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
運行 node index.js
會起一個去 127.0.0.1:3000
的服務,並在瀏覽器中輸出Hello world
瞭解基礎API
path
模塊提供用於處理文件路徑和目錄路徑的實用工具。
// 引用
const path = require('path');
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
// path.resolve() 方法將路徑或路徑片段的序列解析爲絕對路徑
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
fs
文件系統模塊,對文件和目錄進行讀寫操作。
// 引用
const fs = require('fs');
// 讀取文件
fs.readFile('./test.txt', function(err, data) {
if (err) {
throw err;
}
console.log(data);
});
// 寫入文件
fs.writeFile('input.txt', '我是新寫入的內容', function (err) {
if (err) console.error(err);
console.log('數據寫入的數據');
});
// 刪除
fs.unlink('/tmp/hello', (err) => {
if (err) throw err;
console.log('已成功刪除 /tmp/hello');
});
// 重命名
fs.rename('/tmp/hello', '/tmp/world', (err) => {
if (err) throw err;
console.log('重命名完成');
});
更多Api
參考Nodejs Api 官網。