總而言之,Node.js是一個讓JavaScript運行在瀏覽器之外的工具。
對外行來說,這個名字有着嚴重的誤導作用
儘管在StackOverflow上有人說「Java和JavaScript的關係,就像Car和Carpet的關係一樣]
我們還是可以看到這樣的景象:
Node.js = Core JavaScript + Node Standard Library
沒有瀏覽器兼容性問題
基於世界上最快的JavaScript引擎——V8
Node.js標準庫包含了模塊引入、包管理、文件系統、網絡通信、操作系統API等核心JavaScript沒有實現的功能
Node.js使JavaScript不再是腳本語言世界的二等公民
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<h1>Node.js</h1>');
res.end('<p>Hello World</p>');
}).listen(3000);
模塊(Module)是Node.js的基本組成部分,一個文件就是一個模塊
模塊可以是JavaScript代碼文件、JSON文件,或者編譯過的C++擴展
使用require
函數可以加載一個模塊。
var http = require('http');
var os = require('os');
var fs = require('fs');
var vm = require('vm');
var child_process = require('child_process');
創建module.js
,通過exports
對象定義接口:
var name;
exports.setName = function(thyName) {
name = thyName;
};
exports.sayHello = function() {
console.log('Hello ' + name);
};
另一個文件中:
var myModule = require('./module');
myModule.setName('BYVoid');
myModule.sayHello(); // Hello BYVoid
獲取一個包,例如安裝express
:
$ npm install express
express@3.0.3 node_modules/express
├── fresh@0.1.0
├── methods@0.0.1
├── range-parser@0.0.4
├── cookie-signature@0.0.1
├── cookie@0.0.5
├── crc@0.2.0
├── commander@0.6.1
├── debug@0.7.0
├── mkdirp@0.3.3
├── send@0.1.0 (mime@1.2.6)
└── connect@2.7.0 (pause@0.0.1, bytes@0.1.0, formidable@1.0.11, qs@0.5.1)
npm默認使用本地模式,即將包安裝到node_modules
目錄中,而使用全局模式會將包安裝到系統目錄。
使用全局模式安裝一個包:
$ npm install -g less
模式 | 可通過require 使用 |
可以在命令行中使用 |
---|---|---|
本地模式 | 是 | 否 |
全局模式 | 否 | 是 |
如果Node.js僅僅是爲JavaScript包裝了一層運行時環境,它絕對沒有今天這麼火。 異步I/O與事件式編程模型纔是Node.js最大的特點。
同步I/O
res = db.query('SELECT * from some_table');
res.output();
異步I/O
db.query('SELECT * from some_table', function(res) {
res.output();
});
程序執行I/O操作通常要花費很長時間,長達數十萬到數億個CPU指令週期。 因此操作系統和CPU通過中斷實現了異步的調度方式。
進程發起I/O請求時,操作系統會掛起進程,將CPU自由讓給其他工作的進程。 當I/O完成以後,操作系統會使進程繼續執行。 這種請求方式稱爲同步I/O或阻塞式I/O。
異步I/O又叫非阻塞I/O。 指的是進程發起I/O請求以後就繼續執行其他指令,通過其他手段來獲得請求完成的通知。
當非阻塞的I/O發起時,進程不會阻塞,繼續執行事件的其他部分,然後進入事件循環處理其他事件。
異步I/O完成以後會以事件的形式加入事件隊列,等待進程以後進入事件循環時處理。
I/O完成以後的邏輯通過回調函數描述
db.query('SELECT * from some_table', function(res) {
res.output();
});
db.query('SELECT * from some_table', function(res) {
res.output();
});
這段代碼又可以寫成:
db.query('SELECT * from some_table', afterSelect);
function afterSelect(res) {
res.output();
});
阻塞模式下,一個進程只能處理一項任務,哪怕只有一個CPU核,要想提高吞吐量也必須通過多線程。
非阻塞模式下,進程對一個CPU核的利用率永遠是100%,單個線程即可達到單核心的最高吞吐量。
使用回調函數的方法,很容易寫出這樣的代碼:
function func(callback) {
fs.readFile('1.txt', 'utf-8', function (err, contents1) {
if (err) return callback(err);
fs.readFile('2.txt', 'utf-8', function (err, contents2) {
if (err) return callback(err);
fs.writeFile('3.txt', contents1 + contents2, function (err) {
if (err) return callback(err);
callback();
});
});
});
}
Callback Pyramids
var addUser = function(uid, callback) {
mongodb.open(function(err, db) {
if (err) {callback(err); return;}
db.collection('users', function(err, collection) {
if (err) {callback(err); return;}
collection.ensureIndex("uid", function(err) {
if (err) {callback(err); return;}
collection.ensureIndex("username", function(err) {
if (err) {callback(err); return;}
collection.findOne({uid: uid}, function(err) {
if (err) {callback(err); return;}
if (doc) {
callback(new Error('occupied'));
} else {
collection.insert({uid: uid}, function(err) {
callback(err);
});
}
});
});
});
});
});
};
這種通過回調函數進行顯式的控制流傳遞的代碼稱爲「Continuation Passing Style (CPS)」
CPS代碼通常使用嵌套的回調函數來組織,線性的邏輯被拆散到不同的回調函數中
然而,用CPS代碼來描述複雜的邏輯對人工來說,難寫、難調、難改
Continuation.js是一個通過編譯的手段,將嵌套的回調函數平面化的工具。 通過它你可以像寫同步I/O的代碼一樣產生CPS的代碼。
$ npm install -g continuation
通過Continuation.js重寫前面的代碼:
function func(next) {
try {
fs.readFile('1.txt', 'utf-8', obtain(contents1);
fs.readFile('2.txt', 'utf-8', obtain(contents2);
fs.writeFile('3.txt', contents1 + contents2, obtain());
next();
} catch (err) {
next(err);
}
}
使用Continuation.js,你還可以輕易寫出用異步難以描述的邏輯:
var fib = function () {
var a = 0, current = 1;
while (true) {
var b = a;
a = current;
current = a + b;
setTimeout(cont(), 1000);
console.log(current);
}
};
fib();
以上代碼是計算Fibonacci數列,每秒輸出一項。
express
jade
less
uglify-js
socket.io
sequelize
mongoose
node-oauth
grunt
forever
mocha
commander
jison
node-inspector
jsdom
formidable
marked
highlight.js
node-webkit
iconv-lite
imagemagick
continuation
async
fibers
coffee-script
dnode
browserify
jshint
謝謝大家