node學習筆記

一、Node,可讓javascript運行在服務器端的平臺。javascript

   是一個爲實時Web(Real-time Web)應用開發而誕生的平臺。充分考慮了實時響應,超大規模數據要求下架構。java

二、摒棄了傳統平臺依靠多線程來實現高併發的設計思路,而採用了單線程、異步式I/O,事件驅動式的程序設計模型。node

不只帶來了巨大的性能提高,還減小了多線程程序設計複雜性,進而提升了開發效率。shell

三、單線程事件驅動的異步I/O。npm

單線程事件驅動的異步I/O比傳統的多線程阻塞式I/O到底好在哪裏:簡而言這,異步式I/O少了多線程的開銷。對操做編程

系統來講,建立一個線程的代價是十分昂貴的,須要給它分配內存、列入調度,同時在線程切換的時候還要執行內存換頁,緩存

CPU的緩存被清空,切換回來的時候還要從新從內存中讀取信息,破壞了數據的局部性。服務器

四、Node.js 的事件循環機制多線程

Node.js 在何時會進入事件循環呢?答案是 Node.js 程序由事件循環開始,到事件循架構

環結束,全部的邏輯都是事件的回調函數,因此 Node.js 始終在事件循環中,程序入口就是

事件循環第一個事件的回調函數。

五、模塊(Module)和包(Package)是 Node.js 最重要的支柱。

六、事件:Node.js全部的異步I/O操做在完成時都會發送一個事件到事件隊列。在開發者看來,事件由EventEmitter對象提供。

前面提到的fs.readFile和http.createServer的回調函數都是經過EventEmitter來實現的。

七、咱們能夠把要執行的語句做爲node -e的參數直接執行。例如:node -g "cosole.log('Hello World');"

八、使用node的REPL模式。REPL(Read-eval-print loop),即輸入-求值-輸出循環。運行無參數node將會啓動一

個JavaScrit的交互式shell:

例如:                      

進入repl模式後,會出現一個">"提示符提示你輸入命令,輸入後按回車,Node.js將會解析並執行命令。若是你執行了一個函數,那麼REPL還會在下面顯示這個函數的返回值。上面的undefined就是console.log的返回值。若是你輸入了一個錯誤的指令,REPL 則會當即顯示錯誤並輸出調用棧。在任什麼時候候,連續按兩次 Ctrl + C 便可推出Node.js 的 REPL 模式。

node 提出的 REPL 在應用開發時會給人帶來很大的便利,例如咱們能夠測試一個包可否正常使用,單獨調用應用的某一個模塊,執行簡單的計算等。

九、事實上腳本文件的擴展名不必定是js,例如咱們將腳本保存爲script.txt,使用node script.txt命令一樣能夠運行。擴展名使用.js只是一個約定而已,遵循了JavaScript腳本一向的命名習慣。

十、 在開發 Node.js 實現的 HTTP 應用時會發現,不管你修改了代碼的哪一部份,都必須終止Node.js 再從新運行纔會奏效。這是由於 Node.js 只有在第一次引用到某部份時纔會去解析腳本文件,之後都會直接訪問內存,避免重複載入。Node.js的這種設計雖然有利於提升性能,卻不利於開發調試,由於咱們在開發過程當中老是但願修改後當即看到效果,而不是每次都要終止進程並重啓。supervisor 能夠幫助你實現這個功能,它會監視你對代碼的改動,並自動重啓 Node.js。

使用方法很簡單,首先使用 npm 安裝 supervisor:

$ npm install -g supervisor

若是你使用的是 Linux 或 Mac,直接鍵入上面的命令極可能會有權限錯誤。緣由是 npm

須要把 supervisor 安裝到系統目錄,須要管理員受權,可使用 sudo npm install -g

supervisor 命令來安裝。

使用 supervisor 命令啓動 app.js:

$ supervisor app.js

當代碼被改動時,運行的腳本會被終止,而後從新啓動。supervisor 這個小工具能夠解決開發中的調試問題。

十一、回調函數

讓咱們看看在 Node.js 中如何用異步的方式讀取一個文件,下面是一個例子:

//readfile.js

var fs = require('fs');

fs.readFile('file.txt', 'utf-8', function(err, data) {

if (err) {

console.error(err);

} else {

console.log(data);

}

});

console.log('end.');

運行的結果以下:

end.

Contents of the file.

要想理解結果,咱們必須先知道在 Node.js 中,異步式 I/O 是經過回調函數來實現的。fs.readFile 接收了三個參數,第一個是文件名,第二個是編碼方式,第三個是一個函數,咱們稱這個函數爲回調函數。JavaScript 支持匿名的函數定義方式, 譬如咱們例子中回調函數的定義就是嵌套在fs.readFile 的參數表中的。這種定義方式在 JavaScript 程序中極爲廣泛,與下面這種定義方式實現的功能是一致的:

//readfilecallback.js

function readFileCallBack(err, data) {

if (err) {

console.error(err);

} else {

console.log(data);

}

}

var fs = require('fs');

fs.readFile('file.txt', 'utf-8', readFileCallBack);

console.log('end.');

fs.readFile 調用時所作的工做只是將異步式 I/O 請求發送給了操做系統,而後當即

返回並執行後面的語句,執行完之後進入事件循環監聽事件。當 fs 接收到 I/O 請求完成的

事件時,事件循環會主動調用回調函數以完成後續工做。所以咱們會先看到 end.,再看到

file.txt 文件的內容。

十二、模塊和包

模塊(Module)和包(Package)是Node.js最重要的支柱。

Node.js提供了require函數來調用其餘模塊,並且模塊都是基於文件的,機制十分簡單。

咱們常常把Node.js的模塊和包相提並論,由於模塊和包是沒有本質區別的,兩個概念也時常混淆。若是要辨析,那麼能夠把包理解成是實現了某個功能模塊的集合,用於發佈和維護。

1三、模塊是Node.js應用程序的基本組成部分,文件和模塊是一一對應的。換言之,一個Node.js文件就是一個模塊,這個文件多是JavaScript代碼、JSON或者編譯過的C/C++擴展。

例如:var http=require(‘http’),其中http就是Node.js的一個核心模塊,其內部是用C++實現的,外部用javaScript封裝。咱們經過require函數獲取這個模塊,而後才能使用其中的對象。

1四、Node.js提供了exports和require兩個對象,其中exports是模塊公開的接口,require用於從外部獲取一個模塊的接口,即所獲取模塊的exports對象。

讓咱們以一個例子來了解模塊。建立一個 module.js 的文件,內容是:

//module.js

var name;

exports.setName = function(thyName) {

name = thyName;

};

exports.sayHello = function() {

console.log('Hello ' + name);

};

在同一目錄下建立 getmodule.js,內容是:

//getmodule.js

var myModule = require('./module');

myModule.setName('BYVoid');

myModule.sayHello();

運行node getmodule.js,結果是:

Hello BYVoid

在以上示例中,module.js 經過 exports 對象把 setName 和 sayHello 做爲模塊的訪

問接口,在 getmodule.js 中經過 require('./module') 加載這個模塊,而後就能夠直接訪

問 module.js 中 exports 對象的成員函數了。

這種接口封裝方式比許多語言要簡潔得多,同時也不失優雅,未引入違反語義的特性,

符合傳統的編程邏輯。在這個基礎上,咱們能夠構建大型的應用程序,npm 提供的上萬個模

塊都是經過這種簡單的方式搭建起來的。

1五、單次加載

上面這個例子有點相似於建立一個對象,但實際上又和對象有本質區別,由於require不會重複加載模塊,也就是說不管調用多少次require,獲取的模塊都是同一個。

看下列代碼:

//loadmodule.js

var hello1 = require('./module');

hello1.setName('BYVoid');

var hello2 = require('./module');

hello2.setName('BYVoid 2');

hello1.sayHello();

運行後發現結果是Hello BYVoid 2,這是由於變量hello1,hello2指向的是同一對象,由於hello1.setName的結果被hello2.setName覆蓋,最終輸入結果是由後者決定的。

相關文章
相關標籤/搜索