Node.js 最大的特色就是異步式 I/O(或者非阻塞 I/O)與事件緊密結合的編程模式。這 種模式與傳統的同步式 I/O 線性的編程思路有很大的不一樣,由於控制流很大程度上要靠事件 和回調函數來組織,一個邏輯要拆分爲若干個單元html
什麼是阻塞(block)呢?線程在執行中若是遇到磁盤讀寫或網絡通訊(統稱爲 I/O 操做), 一般要耗費較長的時間,這時操做系統會剝奪這個線程的 CPU 控制權,使其暫停執行,同 時將資源讓給其餘的工做線程,這種線程調度方式稱爲 阻塞。當 I/O 操做完畢時,操做系統 將這個線程的阻塞狀態解除,恢復其對CPU的控制權,令其繼續執行。這種 I/O 模式就是通 常的同步式 I/O(Synchronous I/O)或阻塞式 I/O (Blocking I/O)。 4
node
相應地,異步式 I/O (Asynchronous I/O)或非阻塞式 I/O (Non-blocking I/O)則針對 全部 I/O 操做不採用阻塞的策略。當線程遇到 I/O 操做時,不會以阻塞的方式等待 I/O 操做 的完成或數據的返回,而只是將 I/O 請求發送給操做系統,繼續執行下一條語句。當操做 系統完成 I/O 操做時,以事件的形式通知執行 I/O 操做的線程,線程會在特定時候處理這個 事件。爲了處理異步 I/O,線程必須有事件循環,不斷地檢查有沒有未處理的事件,依次予 以處理。git
阻塞模式下,一個線程只能處理一項任務,要想提升吞吐量必須經過多線程。而非阻塞 模式下,一個線程永遠在執行計算操做,這個線程所使用的 CPU 核心利用率永遠是 100%, I/O 以事件的方式通知。在阻塞模式下,多線程每每能提升系統吞吐量,由於一個線程阻塞 時還有其餘線程在工做,多線程可讓 CPU 資源不被阻塞中的線程浪費。而在非阻塞模式 下,線程不會被 I/O 阻塞,永遠在利用 CPU。多線程帶來的好處僅僅是在多核 CPU 的狀況 下利用更多的核,而Node.js的單線程也能帶來一樣的好處。這就是爲何 Node.js 使用了單 線程、非阻塞的事件編程模式github
回調函數web
//readfile.jsshell
var fs = require('fs');
fs.readFile('file.txt', 'utf-8', function(err, data) {編程
if (err) { console.error(err);json
} else { console.log(data);數組
} });網絡
console.log('end.');
運行的結果以下:
end. Contents of the file.
看到沒有各位 先輸出end 後才輸出內容,爲何這樣啊?由於是異步非阻塞的。function就是一個回調函數 。在 Node.js 中,異步式 I/O 是經過回調函數來實現的
fs.readFile 調用時所作的工做只是將異步式 I/O 請求發送給了操做系統,而後當即返回並執行後面的語句,執行完之後進入事件循環監聽事件。當 fs 接收到 I/O 請求完成的事件時,事件循環會主動調用回調函數以完成後續工做。所以咱們會先看到 end.,再看到file.txt 文件的內容
Node.js 在何時會進入事件循環呢?答案是 Node.js 程序由事件循環開始,到事件循環結束,全部的邏輯都是事件的回調函數,因此 Node.js 始終在事件循環中,程序入口就是事件循環第一個事件的回調函數。事件的回調函數在執行的過程當中,可能會發出 I/O 請求或直接發射(emit)事件,執行完畢後再返回事件循環,事件循環會檢查事件隊列中有沒有未處理的事件,直到程序結束
模塊和包
模塊是 Node.js 應用程序的基本組成部分,文件和模塊是一一對應的。換言之,一個 Node.js 文件就是一個模塊,這個文件多是 JavaScript 代碼、JSON 或者編譯過的 C/C++ 擴展
建立及加載模塊
在 Node.js 中,建立一個模塊很是簡單,由於一個文件就是一個模塊,咱們要關注的問 題僅僅在於如何在其餘文件中獲取這個模塊
建立模塊 module.js
var name;
exports.setName = function(mName){
name = mName;
};
exports.sayHello = function() {
console.log('Hello,' + name);
};
建立runModule.js裏面代碼以下:
var module = require('./module.js');
module.setName('greenboy');
module.sayHello();
在shell裏面運行node runModule.js 產生結果以下: