nodejs重要知識點匯總

1.?運行一個nodejs文件积蜻,

如一個js文件中只含有console.log("hello world");的文件,我們再git里運行node玫坛,即 node hello.js 即可發(fā)送輸出hello world。如下:


2.?交互模式

直接輸入node,即進入node環(huán)境昆码,即可輸入任何語句



3.?創(chuàng)建一個簡單的服務器

創(chuàng)建server.js -> require http模塊 -> 調用 createServer 方法進行創(chuàng)建 -> 監(jiān)聽某個端口 -> 運行js文件(實際上是在運行這個node服務器) -> 在瀏覽器中發(fā)送請求。

js文件如下:

其中比較重要的是要知道createServer這個內置函數就是用于創(chuàng)建服務器的邻储,然后接受一個函數作為參數赋咽,我們可以用writeHead方法來寫頭部,使用end方法來輸出內容芥备。用listen來監(jiān)聽端口號冬耿。當然,也可以是監(jiān)聽8889等端口號萌壳,只要是合法的就行亦镶。在瀏覽器端發(fā)出請求,結果如下:



4.?node中的npm


安裝node時就已經安裝了npm袱瓮,即一個包管理工具缤骨,我們一般利用它來安裝一些包,即npm install 如果后面添加 -g 尺借,那么就會將包安全到全局環(huán)境绊起,即user路徑下。如果不添加燎斩,就會安裝在當前文件夾下虱歪,當然首先會創(chuàng)建node_modules文件,在此之下栅表。


一般笋鄙,我們要創(chuàng)建一個項目時,我們可以先npm init怪瓶,通過它萧落,我們就可以創(chuàng)建一個package.json文件,然后通過配置該文件說明我們的項目信息洗贰。其中主要的參數有:

(1)name --- 包名 ? (2)version --- 版本號 ?(3) description --- 包的描述 ? (4)?homepage?--- 包的官網url ?(5)?author?--- 包的作者名字 ?(6)?contributors?--- 包的其他貢獻者名字

(7)dependencies? --- 依賴包列表(如果依賴包沒有安裝找岖,npm 會自動將依賴包安裝在 node_module 目錄下) ? ?(8)repository?--- 包代碼存放的地方 ? (9)main ---?main 字段是一個模塊ID,它是一個指向你程序的主要項目敛滋。就是說许布,如果你包的名字叫 express,然后用戶安裝它绎晃,然后require("express") ? ?(9) keywords --- 關鍵字


卸載模塊: npm uninstall


更新模塊: npm update


版本號相關: 當使用npm下載和發(fā)布代碼時爹脾,都會涉及到版本號相關帖旨,即X-Y-Z,一般而言,只有當版本發(fā)生了重大的變化灵妨,不向下兼容時解阅,X才會變化; 如果增加了新的功能泌霍,仍舊向下兼容 Y 發(fā)生變化货抄; 如果僅僅是做了很小的改變,如修復了bug朱转,那么 Z 發(fā)生變化蟹地。


如果希望知道某條命令的詳細信息,如install的藤为,可以輸入 npm help install


npm連接的是國外的網站怪与,也可以使用淘寶鏡像:

1npm install -g cnpm --registry=https://registry.npm.taobao.org

?然后就可以使用cnpm來安裝了。



5. nodejs REPL

即node的交互式解釋器缅疟,即我們輸入node之后即進入node環(huán)境分别,這個node環(huán)境就是node的交互式解釋器。

值得注意的是存淫,和console控制臺不同耘斩,REPL支持多行輸入,如下所示:

$ node>varx =0undefined>do {

... x++;

... console.log("x: "+ x);

... } while( x <5 );

x: 1x: 2x: 3x: 4x: 5undefined>

一般我們使用ctrl + c來退出該環(huán)境桅咆,大多數情況下括授,我們都是用ctrl+c來退出環(huán)境的。不論是否是node岩饼。



6. nodejs回調函數

在node中荚虚,我們知道其最大的特點就是異步I/O,而實現(xiàn)異步I/O的關鍵就在于回調函數籍茧。

首先版述,我們看看同步的是什么樣:

varfs = require("fs");vardata = fs.readFileSync('test.txt');

console.log(data.toString());

console.log("over");

這是main.js中的代碼,即先引入fs模塊硕糊,然后才能實用相應的API院水,readFileAsync()函數用于同步讀取文件腊徙,它是阻塞的简十,返回這個讀取的文件,輸出如下:


下面這個一個異步的撬腾,

? ? varfs = require("fs");

? ? fs.readFile("test.txt",function (err, data) {

? ? ? ? if (err) {

? ? ? ? ? ? console.log(err);

? ? ? ? } else {

? ? ? ? ? ? console.log(data.toString());

? ? ? ? }

? ? });

? ? console.log("over");

結果如下:

即readFile是一個異步的螟蝙,在執(zhí)行這條語句的時候不會阻塞后面的語句,而是在讀完文件之后再console民傻。

即我們在讀取代碼的時候可以做下面的很多事情胰默,這樣就可以節(jié)省很多時間场斑。

readFile和readFileSync都接受第二個參數,即編碼類型牵署,如"utf-8"




7. nodejs事件循環(huán)

nodejs事件循環(huán)利用的是觀察者模式漏隐,也就是發(fā)布訂閱模式。簡單的理解奴迅,DOM元素綁定事件就是這樣的模式青责。其中綁定的元素是發(fā)布者,函數是訂閱者取具,當元素發(fā)生了變化時(被點擊等)脖隶,就會通知所有的訂閱者。?

nodejs使用事件驅動模型暇检,當服務器接受到了請求之后产阱,就會關閉這個請求,然后再處理块仆,為的是等待下一個請求构蹬。這樣,請求就不會被耽擱榨乎。這個模型的效率非常高怎燥,因為他一直在接受請求,而沒有等待任何讀寫操作蜜暑。在事件驅動模型中铐姚,會生成一個主循環(huán)來監(jiān)聽事件,當檢測到事件時觸發(fā)回調函數:

雖然這里沒有所謂的DOM元素肛捍,但是實現(xiàn)應當是一樣的隐绵,即觀察者模式的最好理解是好萊塢電影中的一句話:?你不要打電話給我,我會打電話給你拙毫。

在node中我們常常使用events模塊來實現(xiàn)依许,即首先引入events,然后創(chuàng)建一個對象缀蹄,利用這個對象的on方法綁定時間峭跳,利用對象的emit方法來觸發(fā)事件,如下所示:

varevents = require("events");vareventEmitter =new events.EventEmitter();

eventEmitter.on("selfDefine", function () {

? ? console.log("This is selfDefine1");

});

eventEmitter.on("selfDefine", function () {

? ? console.log("This is selfDefine2");

});

eventEmitter.on("selfDefine", function () {

? ? console.log("This is selfDefine3");

});

eventEmitter.on("selfDefine", function () {

? ? console.log("This is selfDefine4");

});

eventEmitter.emit("selfDefine");

console.log("over");

最終效果如下:

在這里缺前,我們就可以認為這是發(fā)布訂閱者模式蛀醉,首先可以知道發(fā)布者是selfDefine事件,訂閱者是4個衅码,一旦selfDefine被觸發(fā)显歧,那么就會通知訂閱者慈鸠,方法是將訂閱者添加到了Event Loop中去包个,然后通過事件循環(huán)來監(jiān)聽,一旦被觸發(fā)割捅,就會通知,即我給你打電話帚桩,你沒有給我打電話亿驾。

當事件觸發(fā)時,注冊到這個事件的事件監(jiān)聽器被依次調用账嚎。


另外颊乘,在on和emit中是可以傳遞參數的,如下所示:

varevents = require("events");vareventEmitter =new events.EventEmitter();

eventEmitter.on("selfDefine", function (x) {

? ? console.log("This is selfDefine1 "+ x);

});

eventEmitter.on("selfDefine", function (x) {

? ? console.log("This is selfDefine2 "+ x);

});

eventEmitter.on("selfDefine", function (x) {

? ? console.log("This is selfDefine3 "+ x);

});

eventEmitter.on("selfDefine", function (x) {

? ? console.log("This is selfDefine4 "+ x);

});

eventEmitter.emit("selfDefine","argument");

console.log("over");

最終的效果如下:



關于 EventEmitter 還有其他的屬性醉锄,如下所示:

addListener(event, listener) --- 它和on是類似的乏悄,都是添加某一個事件的監(jiān)聽器

removeListener(event, listener) --- 即通過此API可以將監(jiān)聽器取消(特定的listener)恳不。

removeAllListeners(event) --- 可以取消event下的所有監(jiān)聽器檩小。

newListener(event, listener); --- 該事件在添加新的監(jiān)聽器時被觸發(fā)。

listenerCount(emitter, event); --- 返回指定監(jiān)聽器的數量烟勋。

listeners(event) --- 返回指定事件的監(jiān)聽器數組规求。


once(event, listener) ---?通過once就可以知道,這個監(jiān)聽器只會監(jiān)聽一次卵惦,后面再調用阻肿,就不會監(jiān)聽了。

舉例如下:

varevents = require("events");vareventEmitter =new events.EventEmitter();

eventEmitter.on("foo", function () {

? ? console.log("via on");

});

eventEmitter.once("foo", function () {

? ? console.log("via once");

});

eventEmitter.emit("foo");

setTimeout(function () {

? ? eventEmitter.emit("foo");

}, 1000);


最終的執(zhí)行效果如下:

在執(zhí)行過程中vai on和via once是同時出現(xiàn)的沮尿,過了1s之后丛塌,via on 出現(xiàn), via once不再出現(xiàn)畜疾,因為通過once添加的監(jiān)聽器只會監(jiān)聽一次赴邻,然后就被銷毀了(即后面不再監(jiān)聽)。





8. Nodejs Buffer (緩沖區(qū))

作為服務器端語言的nodejs啡捶,自然會接受請求姥敛,如TCP請求,都是通過二進制來傳遞的瞎暑,但是js語言本身并沒有接受二進制的api彤敛,所以nodejs中添加了Buffer類來作為存儲二進制數據的緩沖區(qū)。

通過Buffer類創(chuàng)建buffer實例的幾種方法:

1. 創(chuàng)建長度為10字節(jié)(1 B = 8 bit)的Buffer類了赌, var buf = new Buffer(10);

2. 通過數組創(chuàng)建Buffer實例墨榄, var buf = new Buffer([10, 20, 30, 15]);

3. 通過一個字符串來創(chuàng)建buffer實例, var buf = new Buffer("i love coding", "utf-8"); 注意: 我們這里使用utf-8格式編碼揍拆,還可以是"ascii", ?"utf16le", "ucs2", "base64" 和 "hex"渠概,當然茶凳,默認就是utf-8嫂拴。

已經有了buffer實例播揪,我們就可以使用buffer實例的一些方法了,如下所示:

write()(寫入數據) ---buf.write(string[,?offset[,?length]][,?encoding])筒狠。它的返回值是寫入的長度猪狈。 ?我們知道[]表示式可選的, 其中string是將要寫入的字符串辩恼; offset是緩沖區(qū)開始寫入的索引值雇庙,默認為0;length是長度灶伊,默認是buf.length疆前; encoding是編碼方式,默認是utf-8聘萨。

toString() (讀取數據)--- buf.toString([encoding[,?start[,?end]]])竹椒。它的返回值是讀取的值。其中的encoding表示讀取數據的編碼方式米辐, start和end表示讀取數據的位置胸完。

toJSON() (轉換為JSON對象)--- buf.toJSON(buf)。 返回值是一個JSON對象翘贮。

Buffer.concat(list[,totalLength]) (合并Buffer對象) --- 返回值是合并后的buffer對象赊窥。其中l(wèi)ist是一個數組,其中的每個元素是一個buffer實例狸页,totalLength是在制定合并之后的總長度锨能。

buf.compare(otherBuffer) (緩沖區(qū)大小比較) --- ?比較兩個緩沖區(qū)的大小,返回 0 -1 1 芍耘。

buf.copy(targetBuffer[,?targetStart[,?sourceStart[,?sourceEnd]]]) (緩沖區(qū)的拷貝

buf.slice([start[,?end]])(緩沖區(qū)的裁剪)

buf.length() --- 返回緩沖區(qū)的長度腹侣。

......


9. Nodejs Stream(流)

Stream是一個抽象的接口,并且它是eventEmitter的實例齿穗,通常Stream有四種流類型傲隶, 包括可讀、可寫窃页、可讀可寫跺株、操作被寫入然后讀出。

  既然它是eventEmitter的實例脖卖,那么就會有事件乒省,這個事件當然不再是自定義然后使用emit的方式,而是已經定義的畦木,不再需要emit了袖扛。 有 data 、end、error蛆封、finish唇礁。其中data表示只要發(fā)現(xiàn)有數據就會立即觸發(fā), end表示沒有更多的數據可讀時就會觸發(fā)惨篱, error是在讀或寫發(fā)生錯誤的時候觸發(fā)盏筐,finish在所有的數據被寫入底層系統(tǒng)時觸發(fā)。

  因為流中的讀寫都是與文件相關砸讳,所以需要引入fs模塊琢融。讀:

varfs = require("fs");varreadStream = fs.createReadStream("./test.txt");

readStream.setEncoding("utf-8");vardata ="";

readStream.on("data", function (chunk) {

? ? data += chunk;

});

readStream.on("end", function () {

? ? console.log(data +" FINISHED");

});

readStream.on("error", function (err) {

? ? console.log(err);

});

  可以看到首先引入文件系統(tǒng)fs,然后使用 createReadStream()方法來讀取文件簿寂, 綁定了data之后漾抬,只要文件中有內容就會被觸發(fā),當讀取文件內容結束之后常遂,就會執(zhí)行end下的監(jiān)聽器奋蔚。 在讀的過程中有錯,就會執(zhí)行error下的監(jiān)聽器烈钞。

  下面是寫操作:(其中的test.js現(xiàn)在內容為空)

varfs = require("fs");varwriteStream = fs.createWriteStream("./test.txt");vardata ="I want to write something";

writeStream.write(data);

writeStream.end();

writeStream.on("finish", function () {

? ? console.log("finished");

});

writeStream.on("error", function (err) {

? ? console.log(err);

});

console.log("ok!");


?  最終輸出為: ok! ? finished

  注意: 我們需要使用end()方法表示結束泊碑,然后當寫入完成之后就會觸發(fā)finish, 最后毯欣,我們打開test.txt就會發(fā)現(xiàn)確實已經寫入了data數據 馒过。


管道流:它提供了這樣的一個機制 --- 從一個流中讀取數據,然后輸入到另一個流中酗钞。

varfs = require("fs");varreadStream = fs.createReadStream("./input.txt");varwriteStream = fs.createWriteStream("./output.txt");

readStream.pipe(writeStream);

console.log("finished");



通過這種方式腹忽,我們就可以將input.txt中的內容流到output.txt之中了。


鏈式流:鏈式是通過連接輸出流到另外一個流并創(chuàng)建多個對個流操作鏈的機制砚作。鏈式流一般用于管道操作窘奏。

引入zlib模塊進行壓縮文件, 之所以說是鏈式流葫录,是因為我們可以連續(xù)使用pipe()着裹,如下所示:

varfs = require("fs");varzlib = require("zlib");varreadStream = fs.createReadStream("./foo.txt");

readStream.pipe(zlib.createGzip()).pipe(fs.createWriteStream("./foo.min.txt"));


即我們首先引入fs模塊和壓縮庫zlib,然后再創(chuàng)建一個讀流米同,通過管道流pipe到壓縮文件骇扇,然后再pipe到一個將要保存壓縮文件的寫文件。最后可以看到foo.min.txt是被壓縮過的面粮。(注意:其中foo.min.txt不需要自己來寫少孝,他會自動生成)

當然我們還可以用createGunzip()方法來解壓縮。




10. nodejs模塊系統(tǒng)

一個nodejs文件就是一個模塊熬苍。我們之前使用var fs = require("fs"); 這里就是引入了一個fs模塊稍走。因為fs是內置的,所以直接引入就好。但是如果是我們自己創(chuàng)建的一個foo.js文件婿脸,我們希望引用這個模塊粱胜,就可以使用var foo = require("./foo"); 即引入當然文件目錄下的foo.js中的模塊。 其中js是默認的盖淡,省略不寫。

我們接觸到的require是nodejs提供的一個接受對象凿歼,與之相對的是exports倒出對象褪迟。

比如我們創(chuàng)建一個foo.js,這就是一個模塊答憔,內容如下:

function Foo() {

? ? this.sayHello = function () {

? ? ? ? console.log("hello world!");

? ? }

}

module.exports = Foo;


即這導出了一個構造函數味赃。 然后我們就可以引入這個module了,如下:

varFoo = require("./foo");varmyFoo =new Foo();

myFoo.sayHello()


這里我們require到了這個模塊虐拓,然后創(chuàng)建了實例心俗,調用了模塊的方法。


服務器端的模塊:之前我們使用的require("http")就是在引入服務器端的模塊蓉驹。 然后再直接調用即可城榛,如createServer()方法。

nojs加載模塊方式如下:

第一步: 判斷文件模塊緩存區(qū)中是否存在模塊态兴。(對于我們之前加載過的模塊狠持,會緩存到緩存區(qū)中,下次最先查找并加載)瞻润。

第二步: 判斷是否是原生模塊喘垂,如http、fs等這就是原生模塊绍撞。 如果判斷一個模塊是原生模塊就會優(yōu)先加載原生模塊正勒。即即使我們有了一個http.json文件,但是由于原生模塊的優(yōu)先級更高傻铣,所以優(yōu)先加載章贞。

第三步: 判斷是否是自定義的模塊。 即我們自己設定的模塊非洲。





11. nodejs函數

  nodejs中的函數也可以作為另一個函數的參數阱驾,同樣也有匿名函數的概念,如下所示:

varhttp = require("http");

http.createServer(function (request, response) {

? ? response.writeHead("200", {"Content-Type":"text/plain"});

? ? response.write("zhuzhenwei,you are handsome!");

? ? response.end();

}).listen(8888);

  這樣就創(chuàng)建了一個服務器怪蔑。

  注意:其中在writeHead中最好寫上charset=utf-8; 后面的字符也可以是utf8里覆、UTF8、UTF-8缆瓣。 他們都是有效的的喧枷。

  例如下面的這個函數,和js中的作用域是一樣的,注意其中我們需要將Content-Type的內容寫成text/plain; charset=utf8; 否則在瀏覽器中輸出漢字時會有問題隧甚。

varhttp = require("http");

http.createServer(function (req, res) {

? ? ? ? ? ? res.writeHead(200, {"Content-Type":"text/html; charset=utf8"});

? ? ? ? ? ? if(req.url !=="/favicon.ico") {// 清除第二次訪問console.log("訪問");

? ? ? ? ? ? ? ? a(res);

? ? ? ? ? ? ? ? res.write("Hello world!");

? ? ? ? ? ? ? ? res.end();?

? ? ? ? ? ? }

}).listen(8081);

function a(res) {

? ? res.write("hello, 我是一個被調用的函數车荔。");

}

console.log("Server running at http:127.0.0.1:8081");

  其中的req.url !== "/favicon.ico"是為了解決自身的bug的。?



上面的這種方式是對于一個內部的函數而言的戚扳,但是如果我們希望是一個外部文件的函數應該怎么辦呢忧便??

如下,建立一個fun2.js帽借,和server.js在同一個文件下珠增,內容如下:

function a2(res) {

? ? res.write("我是fun2調用的函數");

}

module.exports = a2;

注意:最后一句的意思是我們希望將這個函數導出,如果不導出去砍艾,就沒有辦法使用蒂教。然后server.js內容如下:

varhttp = require("http");varotherfun = require("./fun2");

http.createServer(function (req, res) {

? ? ? ? ? ? res.writeHead(200, {"Content-Type":"text/html; charset=utf8"});

? ? ? ? ? ? if(req.url !=="/favicon.ico") {// 清除第二次訪問console.log("訪問");

? ? ? ? ? ? ? ? otherfun(res);

? ? ? ? ? ? ? ? res.write("Hello world!");

? ? ? ? ? ? ? ? res.end();?

? ? ? ? ? ? }

}).listen(8081);

console.log("Server running at http:127.0.0.1:8081");

注意: 其中如果我們要使用這個函數,就必須要用otherfun來調用脆荷,雖然在fun2中的函數名是fun2凝垛,但是在server.js中只認otherfun。?

  另外蜓谋,因為這是一個本地的文件梦皮,我們最好在前面加上./ 表示相對位置。

缺點:可以看到這樣桃焕,我們每次只能在一個文件中導出一個函數届氢,但是對于一個文件中有多個函數的情況應該怎么導出呢? 如下所示:

module.exports = {

? ? func2 : function (res) {

? ? ? ? res.write("我是func2函數");

? ? },

? ? func3 : function (res) {

? ? ? ? res.write("我是func3函數");

? ? }

};

即將函數使用對象的形式定義覆旭,然后我們導出這么個對象退子,就向http一樣,我們引入這個http對象之后型将,然后使用http.createServer等方法寂祥。?

調用的時候顯然就是下面這樣的,調用對象的方法:

varhttp = require("http");varfun = require("./fun.js");

http.createServer(function (req, res) {

? ? ? ? ? ? res.writeHead(200, {"Content-Type":"text/html; charset=utf8"});

? ? ? ? ? ? if(req.url !=="/favicon.ico") {// 清除第二次訪問console.log("訪問");

? ? ? ? ? ? ? ? fun.func2(res);

? ? ? ? ? ? ? ? fun.func3(res);

? ? ? ? ? ? ? ? res.end();?

? ? ? ? ? ? }

}).listen(8081);

console.log("Server running at http:127.0.0.1:8081");

效果如下:

所以七兜,可以看到丸凭,后者可以調用多個函數,一般就用后面這種形式腕铸。

另外惜犀,我們還經常用字符串的形式,如fun["func2"]或者fun["func3"]狠裹,這樣的好處是:我們可以把調用寫活了虽界,在后面講到路由的時候更為重要,因為可以把字符串作為一個變量涛菠,輸入不同的值莉御,就可以調用不同的函數撇吞,?非常重要。礁叔。


12. nodejs路由(重點)

我們所需要的數據都在request對象中牍颈,另外,我們得先解析url琅关,需要引入url模塊和querystring模塊煮岁。

即url.parse()可以解析這個url。

對于客戶端輸入的url涣易,我們通過request.url即可獲取画机。

這里比較難理解。都毒。色罚。


13. nodejs全局對象

與瀏覽器中window作為全局不同碰缔,在node中global是全局對象账劲,我們可以直接在全局對象上定義屬性,那么就可以訪問到了金抡,指的注意的是瀑焦,由于每一個nodejs模塊都是一個作用域,所以直接var是局部變量梗肝,而不是全局變量榛瓮。

__filename --- 這個全局變量表示運行的nodejs的文件名。

__dirname --- 表示目錄名稱(不包含文件名)

在文件中的代碼如下:

console.log(__filename);

console.log(__dirname);


輸出如下:

可以看出巫击,其中__filename是包含了路徑的禀晓。 而__dirname僅僅是缺少了文件名,只有路徑坝锰。


另外粹懒,console、setTimeout顷级、clearInterval等等都是全局對象凫乖,舉例如下:

console.time("set");varTimer = setInterval(function () {

? ? console.log(__dirname);

}, 1000);

setTimeout(function () {

? ? clearInterval(Timer);

? ? console.log("cleared");

},5000);

console.timeEnd("set");

console.info("info");

console.warn("warn");

console.log("my birthday is %d",19950628);


最終的輸入如下:

可以看到,由于setInterval和setTimeout是非阻塞的弓颈,所以后面的語句先執(zhí)行帽芽,指的注意的是其中的console.log("%d",19950628)的應用,這與C語言中的printf是非常相似的翔冀。另外console.trace()可以追蹤調用棧导街。

另外還有一個比較重要的api,即setImmediate(handler); 他是IE10中支持的纤子。其他的瀏覽器一律不支持菊匿,但是node是支持的付呕,這個解決單線程阻塞的問題,當然用setTimeout(handler, 0);也可以跌捆,但是后者的延遲時間較前者更長一些狈邑。


process也是一個全局變量趁尼,在node環(huán)境下輸入global.process就可以看到其中具有的變量,因為process本身就是一個對象。不難理解process是描述進程(process即進程的意思)的一個全局對象城侧。

他還有一些事件,如下:

舉例如下:

setImmediate(function () {

? ? console.log("god");

});

process.on("exit", function (code) {

? ? console.log("exitCode is:", code);

});

console.log("over");



即進程一旦結束截型,就會觸發(fā)監(jiān)聽器蚕泽。 注意:這里使用on的方式,所以我們可以認為process是eventEmitter的實例钙姊。

輸入如下:

退出碼為0是什么意思呢? ?因為每當exit事件觸發(fā)毯辅,都會有一個code即退出碼,表示這個退出的方式煞额,0表示正常退出思恐,一般還有如下幾種退出碼:


process 不僅提供了上述事件,還提供了非常多的有關進程的屬性膊毁,如pid(進程號)胀莹、platform(程序運行的平臺)、archf(當前CPU的架構)婚温、title(進程名描焰,默認為node)、versions(包含了node的版本和依賴)栅螟、version(node的版本)荆秦、execPath(當前腳本的二進制文件路徑)、stdin力图、stdout步绸、stderr。舉例如下:

console.log(process.platform);

console.log(process.version);

process.stdout.write("hello world \n");

console.log(process.execPath);


注意:其中的stdout.write是在終端輸出搪哪,那么什么時候才能在頁面上輸出呢靡努? ?顯然,由于node是服務器端語言晓折,所以說只能通過響應(response)的方式才能返回給客戶端惑朦。


下面的process方法也是常用的:

console.log(process.memoryUsage());

console.log(process.cwd());


其中第一個是內存使用情況。后者是cwd(current working directory)即當前工作目錄漓概。

可以看到rss漾月、heapTotal、heapUsed表示了內存使用情況胃珍。




14. nodejs常用工具

這里需要介紹的工具梁肿,首先要引入util模塊蜓陌,主要有util.inherits、util.inspect吩蔑、util.isArray(object)钮热、util.isRegExp(object)、util.isDate(object)烛芬、util.isError(object)隧期。


util.inherits(subconstructor, supconstructor),

即這個方法可以實現(xiàn)繼承,但是這里的繼承和我們使用js實現(xiàn)的繼承也有不同之處赘娄,主要區(qū)別是這里的繼承是原型對象之間的繼承仆潮,而不會繼承上一級的構造函數,舉例如下:

varutil = require("util");

function Sup() {

? ? this.name ="sup";

? ? this.sayHello = function () {

? ? ? ? console.log(this.name);

? ? }

}

Sup.prototype.show = function () {

? ? console.log("just show yourself");

}

function Sub() {

? ? this.name ="sub";

}

util.inherits(Sub, Sup);varobjSup =new Sup();

console.log(objSup.name);varobjSub =new Sub();

objSub.show();// objSub.sayHello(); // 報錯遣臼, objSub.sayHello() is not a function.


這里可以看到其中的objSub.show()成功繼承了Sup的原型中的方法性置,但是objSub.sayHello()卻會報錯,因為通過util.inherits()的方式是不能繼承構造函數中的方法的揍堰,與js中的不一樣鹏浅,需要注意。


util.inspect(obj)

這里并不是只有一個參數个榕,它實際上還可以接受三個篡石,第二個是true/false芥喇,表示是否顯示更多的信息西采,第三個是depth,即遞歸的層數,默認是2層继控; 第四個是關于顏色的true/false械馆。舉例如下:

varutil = require("util");

function Foo() {

? ? this.age =21;

? ? this.name ='zzw';

? ? this.sayHello = function () {

? ? ? ? console.log(this.age);

? ? }

}

console.log(util.inspect(Foo));

console.log(util.inspect(Foo, true));


最終的輸出如下:

可以看到,沒有第二個參數武通,那么只會輸出簡單的一個函數霹崎,如果為true,就會輸出更多深層次的內容冶忱。


util.isArray()

實際上尾菇,這里和js中的Array.isArray()是一樣的,舉例如下:

varutil = require("util");

console.log(util.isArray([])); //trueconsole.log(util.isArray(newArray()));//trueconsole.log(util.isArray({}));//true



util.isRegExp() 即判斷是否是一個正則表達式


util.isDate() 即判斷是否是一個日期


util.isError() 即判斷是否是一個錯誤對象



15. nodejs 文件系統(tǒng)

nodejs作為后臺語言囚枪,必然不可避免的需要和數據庫文件等打交道派诬,所以文件系統(tǒng)模塊是非常必要的。即file system --- 文件系統(tǒng)链沼。

在node中的fs中默赂,所有的方法均有同步和異步之分。如同步讀取文件括勺,fs.readFile()缆八;異步讀取文件曲掰,fs.readFileSync()。如下所示:

varfs = require("fs");// 異步讀取fs.readFile('input.txt', function (err, data) {

? if (err) {

? ? ? return console.error(err);

? }

? console.log("異步讀取: "+ data.toString());

});// 同步讀取vardata = fs.readFileSync('input.txt');

console.log("同步讀取: "+ data.toString());

console.log("程序執(zhí)行完畢奈辰。");


ok栏妖! ?下面介紹一些node中常用的文件操作api。

打開文件

varfs = require("fs");

console.log("準備打開文件");

fs.open("foo.txt","r+",function (err, fd) {

? ? if (err) {

? ? ? ? return? console.log(err);

? ? }

? ? console.log("成功打開文件");?

});


即第一個參數是要打開的文件的路徑奖恰,第二個參數是打開的flag(方式)底哥,第三個參數是回調函數,即如果打開錯誤房官,返回輸出錯誤趾徽,否則輸出成功打開文件。

其中flag有下面的方式:?

r 讀模式打開文件

r+ ?讀寫模式打開文件

rs 同步方式打開文件

rs+ 同步方式打開和讀寫文件

w ?寫入方式打開文件

w+ 讀寫方式打開文件翰守,如果沒有孵奶,就創(chuàng)建

。蜡峰。了袁。


獲取文件的相關信息

舉例如下:

輸入如下所示:

varfs = require("fs");

fs.stat("foo.txt", function (err, stats) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log(stats);

? ? console.log(stats.isFile());

? ? console.log(stats.isDirectory());

});


輸出如下所示:

$ node inherits

{ dev: 917962,

? mode: 33206,

? nlink: 1,

? uid: 0,

? gid: 0,

? rdev: 0,

? blksize: undefined,

? ino: 3377699720545815,

? size: 60,

? blocks: undefined,

? atime: 2017-04-12T12:30:03.350Z,

? mtime: 2017-04-12T12:30:33.144Z,

? ctime: 2017-04-12T12:30:33.144Z,

? birthtime: 2017-04-12T12:30:03.228Z }truefalse


可以看出fs.stat()接受兩個參數,第一個是文件名湿颅,第二個是一個回調函數载绿,回調函數中有兩個參數 ,第一個參數是err油航,即發(fā)生錯誤時我們return崭庸,并且console.log(err),所以最終是return console.log(err); 第二個參數

是stats,實際上是fs.stats對象谊囚,這個對象中包含了很多關于這個文件的詳細信息---包括uid怕享、gid、size镰踏、birthtime等函筋。



寫入文件

varfs = require("fs");

fs.writeFile("input.txt","somethingsomethingsomething", function (err) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log("seccess!");

? ? fs.readFile("input.txt", function (err, data) {

? ? ? ? if (err) {

? ? ? ? ? ? return console.log(err);

? ? ? ? }

? ? ? ? console.log(data.toString());

? ? });

});


?即這里首先引入了fs,然后寫文件函數接受三個參數奠伪,第一個是將要寫的文件(如果之前沒有跌帐,就創(chuàng)建之后再寫入),第二個是要寫入的內容绊率, 第三個是一個匿名函數谨敛,如果出錯,就返回錯誤即舌,否則佣盒,讀取文件,其中函數的第二個參數data即文件的內容顽聂,利用toString()就能還原肥惭。



創(chuàng)建目錄

varfs = require("fs");

fs.mkdir("./new", function (err) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log("seccess!");

});


?這樣盯仪,就可以在當前目錄下創(chuàng)建一個new文件夾了。 注意: 最好使用相對路徑蜜葱。?


讀取目錄

varfs = require("fs");

fs.readdir("./some", function (err, files) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? files.forEach(function (file) {

? ? ? ? console.log(file);

? ? });

});


注意:在當前的some文件夾下有兩個txt文件全景,我們只要給readdir()的第二個參數傳入一個函數,第二個參數是files(即文件夾中的所有文件)牵囤,就可以通過forEach來遍歷輸出了爸黄。結果如下:

df.txt

g.txt


?這里回顧一下forEach的用法:

vararr = [1,2,3,4,5,6,7,8,9];

arr.forEach(function (value) {

? ? ? console.log(value);

});


即forEach用于數組,它接受一個函數作為參數揭鳞,函數的參數就是要遍歷的數組中的每一個值炕贵,最終的結果如下:


刪除目錄

varfs = require("fs");

fs.rmdir("./ha", function (err) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log("success");

});


注意:刪除目錄時,只能刪除文件夾中沒有文件的文件夾野崇,否則無法刪除成功称开。那么怎么刪除文件呢?如下:



刪除文件

varfs = require("fs");

fs.unlink("./foo.txt", function (err) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log("seccess!");

});


這樣就可以刪除掉當前頁面下的foo.txt文件乓梨。 即unlink鳖轰,不再相關的意思。如果希望刪除其他文件夾下的文件也非常簡單扶镀,如下:

varfs = require("fs");

fs.unlink("./some/g.txt", function (err) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log("seccess!");

});


?即修改相對路徑即可完成蕴侣。


關閉文件

fd---file descriptor 文件描述符

varfs = require("fs");varbuf =newBuffer(1024);

console.log("準備打開文件!");

fs.open('input.txt','r+', function(err, fd) {

? if (err) {

? ? ? return console.error(err);

? }

? console.log("文件打開成功臭觉!");

? console.log("準備讀取文件昆雀!");

? fs.read(fd, buf, 0, buf.length,0, function(err, bytes){

? ? ? if (err){

? ? ? ? console.log(err);

? ? ? }

? ? ? // 僅輸出讀取的字節(jié)if(bytes >0){

? ? ? ? console.log(buf.slice(0, bytes).toString());

? ? ? }

? ? ? // 關閉文件? ? ? fs.close(fd, function(err){

? ? ? ? if (err){

? ? ? ? ? ? console.log(err);

? ? ? ? }

? ? ? ? console.log("文件關閉成功");

? ? ? });

? });

});


其中input.txt中是有內容的,重要的是在open方法的參數中胧谈,第三個參數的第二個是fd---文件描述符忆肾,即必須通過文件描述符來read和close荸频。



16.?nodejs GET/POST 請求(重點)

nodejs是服務器端語言菱肖,當然要和瀏覽器打交道,所以處理get旭从、post請求是非常必要的稳强。

獲取get請求內容

varhttp = require("http");varutil = require("util");varurl = require("url");

http.createServer(function (req, res) {

? ? res.writeHead(200,{"Content-Type":"text/plain"});

? ? res.end(util.inspect(url.parse(req.url)));

? ? console.log(url.parse(req.url).path);

}).listen(3000);


?這里引入了util模塊用于inspect,引入了url模塊用于parseGET請求的url和悦。 注意我們再parse之后得到的是一個對象退疫,這個對象中包含了req.url的詳細信息。瀏覽器效果如下:

即nodejs就相當于運行了本地服務器鸽素,我們使用localhost:3000即表示訪問我們本地服務器的3000端口褒繁。和127.0.0.1:3000的效果是一樣的。

varhttp = require("http");varurl = require("url");

http.createServer(function (req, res) {

? ? res.writeHead(200,{"Content-Type":"text/plain"});

? ? varparams= url.parse(req.url,true).query;

? ? res.write(params.name+"\n");

? ? res.write(params.age);

? ? res.end();

}).listen(3000);


最終的結果如下:


獲取POST請求內容

使用post請求后馍忽,需要我們使用nodejs在后臺利用req.on和querystring.pase來手動解析post請求棒坏。

一個含有post請求的頁面如下:

? ? ? ? for_post? ? ? ? ? ? name:
? ? ?

? ? ? ? age:

? ? ? ? ? ?


nodejs的文件如下:

varhttp = require("http");varfs = require("fs");varquerystring = require("querystring");

http.createServer(function (req, res) {

? ? varbody ="";

? ? req.on("data", function (chunk) {

? ? ? ? body += chunk;

? ? });

? ? req.on("end", function () {

? ? ? ? body = querystring.parse(body);

? ? ? ? res.writeHead(200, {'Content-Type':'text/html; charset=utf8'});

? ? ? ? if(body.name && body.age) {

? ? ? ? ? ? console.log("true");

? ? ? ? ? ? res.write("The client is "+body.name);

res.write("
");? ? ? ? ? ? res.write(

"This clent is "+ body.age +" years old");

? ? ? ? ? ? res.end();

? ? ? ? } else {

? ? ? ? ? ? console.log("else");

? ? ? ? ? ? fs.readFile("./post.html", function (err, data) {

? ? ? ? ? ? ? ? if (err) {

? ? ? ? ? ? ? ? ? ? return console.log(err);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? res.write(data);

? ? ? ? ? ? ? ? res.end();

? ? ? ? ? ? });

? ? ? ? }

? ? });

}).listen(8888);


最終的效果如下:

good燕差! ?這個也很容易嘛!



17. nodejs工具模塊

?nodejs中提供了很多好用的模塊坝冕,如下:

OS模塊 --- 提供基本的系統(tǒng)操作函數

?Path模塊 --- 提供了處理和轉換文件的工具

Net模塊 --- ?用于底層的網絡通信徒探,提供了網絡端和服務器端的模塊

Dns模塊 --- 用于解析域名

Domain模塊 --- 簡化異步代碼的異步處理,可以捕捉try-catch無法捕捉的喂窟。


OS模塊

varos = require("os");// 操作系統(tǒng)的默認臨時文件夾console.log(os.tmpdir());//C:\Users\ADMINI~1\AppData\Local\Temp// 操作系統(tǒng)的字節(jié)序console.log(os.endianness());// LE// 操作系統(tǒng)的主機名console.log(os.hostname());//718JVP8AUMCTA6H // 操作系統(tǒng)名console.log(os.type());// window_NT 注意XP等系統(tǒng)都是基于window_NT發(fā)展的// 操作系統(tǒng)console.log(os.platform());// win32// 操作系統(tǒng)的發(fā)行版本console.log(os.release());// 10.0.14393? 我的系統(tǒng)是win10的// 系統(tǒng)內存總量console.log(os.totalmem());// 8475926528// 系統(tǒng)的空閑內存console.log(os.freemem());// 4304961536// CPU的信息console.log(os.cpus());


CPU信息如下:

即四核的CPU测暗,基本相同,urse略有差別 磨澡。


Path()模塊

這個模塊主要給了一些處理路徑的api碗啄,如規(guī)范化路徑、拼接路徑稳摄、返回后綴名等挫掏,舉例如下:

varpath = require("path");

console.log("normalization:"+ path.normalize('/test/test1//test2..'));

console.log("joinPath:"+ path.join('test','test1/','/test2'));

console.log("toAbsolute:"+ path.resolve("main.js"));

console.log("extName:"+ path.extname("main.js"));


結果如下所示:

normalization:\test\test1\test2..

joinPath:test\test1\test2

toAbsolute:C:\Users\Administrator\Desktop\node\main.js

extName:.js



Net()模塊

這里的內容非常多,等需要的時候再深入學習秩命。



Dns模塊

dns模塊中也有不少內容尉共,但是還不知道具體的作用,下面的例子應該是常用的:

vardns = require("dns");

dns.lookup("www.baidu.com", function onLookup(err, address) {

? ? if (err) {

? ? ? ? return console.log(err);

? ? }

? ? console.log(address);

});


這樣弃锐,就可以解析出www.baidu.com的域名袄友,通過address即可輸出119.75.217.109



Domain模塊

這個模塊主要用于簡化異常處理。



18. nodejs Web 模塊

?使用node創(chuàng)建web服務器端

? 大多數web服務器都支持服務器端腳本語言霹菊,如ruby剧蚣、python、php等旋廷,并通過腳本語言鸠按,從數據庫獲取數據,將結果返回給客戶端瀏覽器饶碘, 目前主流的服務器是Apache目尖、Nginx和IIS。

 當然扎运,這里講的是node瑟曲, 使用node就可以創(chuàng)建一個服務器。即引入http模塊創(chuàng)建豪治。

 下面的演示是一個最基本的服務器架構:

varhttp = require("http");varfs = require("fs");varurl = require("url");

http.createServer(function (req, res) {

? ? varpath = url.parse(req.url).pathname;

? ? fs.readFile(path.substr(1), function (err, data) {

? ? ? ? if (err) {

? ? ? ? ? ? console.log(err);

? ? ? ? ? ? res.writeHead(404, {"Content-Type":"text/html"});

? ? ? ? } else {

? ? ? ? ? ? res.writeHead(200, {"Content-Type":"text/html"});

? ? ? ? ? ? res.write(data.toString());

? ? ? ? ? ? res.end();

? ? ? ? }

? ? });

}).listen(8081);

console.log("Server running at http:127.0.0.1:8081");

 演示如下:


?使用node創(chuàng)建web客戶端

?注意:服務端還用之前的server.js洞拨,下面為client.js

varhttp = require("http");varoptions = {

? ? host: "localhost",

? ? port: "8081",

? ? path: "/index.html"};varcallback = function (res) {

? ? varbody ="";

? ? res.on("data", function (data) {

? ? ? ? body += data;

? ? });

? ? res.on("end", function () {

? ? ? ? console.log(body);

? ? });

};varreq = http.request(options, callback);

req.end();


  首先在終端運行server.js,然后再打開一個終端负拟,運行client.js烦衣,可以發(fā)現(xiàn)輸出如下:

? ? ? ? index? ? ? ? ? ? h1 {

? ? ? ? ? ? color: red;

? ? ? ? }

? ? ? ?

hello,thisisthe index.html.




19. nodejs Express框架

jQuery是客戶端js的框架,同樣Express是服務器端nodejs的框架,它提供了一系列的強大特性幫助我們快速構建web應用花吟,也提供了豐富的http工具启泣。使用Express可以快速搭建一個功能完整的網站。

Express的核心特性是:

設置中間件來響應http請求示辈。

制定路由表寥茫,來響應不同的http請求操作。

通過向模板傳遞參數矾麻,動態(tài)渲染html纱耻。

更多內容看《nodejs 之 Express 框架》。


20.?nodejs RESTful API

?REST 即表述性狀態(tài)轉移险耀, Representional State Transfer弄喘, 這是一種軟件架構風格。表述性狀態(tài)轉移是一組架構約束條件和原則甩牺。滿足這些條件的程序就是RESTful蘑志,或者說基于REST架構的web service就是RESTful。

創(chuàng)建RESTful



?21. nodejs 多進程

引入child_process模塊就可以使用它的api來創(chuàng)建多進程贬派。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末急但,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子搞乏,更是在濱河造成了極大的恐慌波桩,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件请敦,死亡現(xiàn)場離奇詭異镐躲,居然都是意外死亡,警方通過查閱死者的電腦和手機侍筛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門萤皂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匣椰,你說我怎么就攤上這事裆熙。” “怎么了窝爪?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵弛车,是天一觀的道長。 經常有香客問我蒲每,道長,這世上最難降的妖魔是什么喻括? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任邀杏,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘望蜡。我一直安慰自己唤崭,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布脖律。 她就那樣靜靜地躺著谢肾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪小泉。 梳的紋絲不亂的頭發(fā)上芦疏,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音微姊,去河邊找鬼酸茴。 笑死,一個胖子當著我的面吹牛兢交,可吹牛的內容都是我干的薪捍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼配喳,長吁一口氣:“原來是場噩夢啊……” “哼酪穿!你這毒婦竟也來了?” 一聲冷哼從身側響起晴裹,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤昆稿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后息拜,有當地人在樹林里發(fā)現(xiàn)了一具尸體溉潭,經...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年少欺,在試婚紗的時候發(fā)現(xiàn)自己被綠了喳瓣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡赞别,死狀恐怖畏陕,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情仿滔,我是刑警寧澤惠毁,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站崎页,受9級特大地震影響鞠绰,放射性物質發(fā)生泄漏。R本人自食惡果不足惜飒焦,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一蜈膨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦翁巍、人聲如沸驴一。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肝断。三九已至,卻和暖如春驰凛,著一層夾襖步出監(jiān)牢的瞬間胸懈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工洒嗤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留箫荡,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓渔隶,卻偏偏與公主長得像羔挡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子间唉,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354