關於 Node.js®
作為一個非同步事件驅動的 JavaScript 執行環境,Node.js 被設計來打造可擴充的網路應用程式。下方的 hello world 範例可以處理多個併發的連線,每個連線都會觸發回呼函式,但若沒有任務可執行,Node.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');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
這與目前常見使用作業系統行程的併發模型形成鮮明對比,基於行程的網路操作相較之下更沒效率也更難使用。除此之外,因為沒有結的存在,Node.js 的使用者毋須擔心行程死結(deadlock)的問題。Node.js 中幾乎所有的函式都不能直接操作 I/O,因此行程從不阻塞,也因不阻塞,可擴充的系統在 Node.js 中也就水到渠成。
若你仍對上述說明有不清楚的地方,請參閱阻塞 vs. 非阻塞。
Node.js 的設計上受到 Ruby Event Machine 和 Python Twisted 的啟發,且更近一步將事件迴圈作為一個執行環境中的結構,而非一個函式庫。在其他系統中,事件迴圈開始前都會有個阻塞的呼叫。
通常執行的行為是透過腳本開頭的回呼函式定義的,接著再透過像 EventMachine::run()
這樣的阻塞呼叫來啟動伺服器,在 Node.js 中並沒有這樣的啟動事件迴圈呼叫,Node.js 在執行輸入的腳本後會直接進入事件迴圈,並在沒有任何回呼函式可呼叫時退出事件迴圈,這樣的行為就跟在瀏覽器中的 JavaScript 一樣,整個事件迴圈都在背後進行。
HTTP 是 Node.js 世界中的一等公民,設計之初就考量到了 stream 及低延遲,這使的 Node.js 相當適合作為網頁函式庫或框架的基礎。