摘要:的介紹一般是這樣在中,類是隨內核一起發布的核心庫。庫為帶來了一種存儲原始數據的方法,可以讓處理二進制數據,每當需要在中處理操作中移動的數據時,就有可能使用庫。這樣傳遞數據會更快。
零、開始之前 1、 首先解釋一下node.js是什么? 2、node.js和javascript有什么不同?
1)因為javascript主要是用在browser,而node.js是在server或者你的電腦上寫,所以就不會有window / document這兩個變量,取而代之的是global / process.
global和window一樣,也有很多內置的function和variables,比如setTimeout() / setInterval() / console..., 不過也有很多不同,這個后面會慢慢講;
node.js里很重要的一個概念就是modules。除了一些core modules(比如events/http/fs/url...), 還可以用require()來引進一些自定義的modules。
比如:
//stuff.js var counter = function(arr){ return "There are "+ arr.length+ " arguments." }; var adder = function(a,b){ return `the sum is ${a+b};` }; var pi = 3.1415926;
如果要在其他的file里用這個counter function應該怎么做呢?
在stuff.js后面加上:
//第一種方法 //modules.exports是一個object對象 modules.exports.counter = counter; modules.exports.adder = adder; modules.exports.pi = pi;
上面的方法意思是到了,但是比較復雜,我們可以用對象的方式來寫modules.exports
//第二種方法 modules.exports = { counter: counter, adder: adder, pi: pi }
還有一種辦法直接寫在上面的functions里:
modules.exports.counter = function(arr){ return "There are "+ arr.length+ " arguments." }; modules.exports.adder = function(a,b){ return `the sum is ${a+b};` }; modules.exports.pi = 3.1415926;
然后要引用的時候使用require():
//main.js var stuff = require("./stuff"); //可以不用寫extension name,node自己會補上; //使用一下: console.log(stuff.counter(["hello", "world"]); console.log(stuff.adder(5, stuff.pi);二、EventEmitter類
在node.js里,有一個core module是event,event里只有一個對象,就是EventEmitter, 主要用于封裝事件觸發和事件監聽器的功能(使用javascript里的觀察者模式)。
如果用過jquery的話,對這個格式一定不陌生:
button.on("click", function(){alert("clicked!");}
其實node里的EventEmitter和jQuery的這個事件監聽函數的寫法也很類似:
//首先引入EventEmitter對象 //EventEmitter是一個constructor,可以使用原型繼承 var eventEmitter = require("event").EventEmitter; var event = new eventEmitter(); //綁定事件 event.on("data", function(str){ console.log("something here: "+ str.toString()); }; //觸發事件 //前一個param是event的名字,后一個是callback函數需要的變量 event.emit("data", "Tom wants sth to eat.");
前面提到EventEmitter其實是一個constructor,可以通過prototype繼承;
我們現在用util這個module來實現node里的inherits:
var event = require("event"); var util = require("util"); //創造一個person的constructor,一會來繼承eventEmitter; var Person = function(name){ this.name = name; }; //util.inherits用來繼承,注意兩個params的順序; util.inherits(Person, event.EventEmitter); //現在我們來new兩個person實例出來: var james = new Person("james"); var ellen = new Person("ellen"); //放在一個叫people的array里: var people = [james, ellen]; //現在用eventEmitter里的on方法綁定事件; //因為Person實例已經繼承,所以可以使用 people.forEach(function(person){ person.on("speak", function(str){ console.log(`${person} says ${str}`); }); }); //觸發事件 james.emit("speak", "good morning!"); ellen.emit("speak", "good evening!");三、fs (file system) 類
fs類主要是用來處理文件的,有非常多的方法,但在這個小教程里只涉及read和write兩項。
首先我們來區分一下“同步”和“異步”的概念:
“同步”—— blocking; 解析器會一步一步地解析你的code,如果前面那行沒操作完就不會操作后面那行;
“異步”——non-blocking;解析器解析完這行代碼之前,不會妨礙到后面代碼的進行,在異步處理完后通過callback函數對結果進行處理,因此,異步的性能比同步會很多。
//node中同步read和write的寫法: var fs = require("fs"); //同步是"readFileSync" var readMe = fs.readFileSync("input.txt", "utf8"); fs.write("output.txt", readMe); //異步: //err是出現的錯誤,data是readFile后讀取到的數據 fs.readFile("input.txt", "utf8", function(err, data){ if(err){ console.error(err); }else{ fs.writeFile("output.txt", data); }
可以看到,運用fs的callback函數,可以直接在readFile里寫writeFile, 不需要重新定義變量。
再寫一個fs中的建立目錄和移除目錄的方法,同樣有同步和異步兩種方式:
var fs = require("fs"); //make a directory sync fs.mkdirSync("stuff"); //delete a directory sync fs.rmdirSync("stuff"); //make a directory async fs.mkdir("stuff", function(){ fs.readFile("readMe.txt", "utf8", function(err,data){ fs.writeFile("./stuff/writeMe/txt", data); }); }); //remove a directory async //you must first remove all files in this directory, then you can delete this folder fs.unlink("./stuff/writeMe.txt", function(){ fs.rmdir("stuff"); })四、Stream類
在解釋stream之前,首先我們來想一想為什么要有readable stream和writable stream呢? 明明fs類里就有readFile和writeFile的方法啊,何必還要再添加stream來找麻煩呢?
要知道這兩個之間的不同,讓我們來理一下"buffer"的概念。
buffer的介紹一般是這樣:
在Node.js中,Buffer類是隨Node內核一起發布的核心庫。Buffer庫為Node.js帶來了一種存儲原始數據的方法,可以讓Nodejs處理二進制數據,每當需要在Nodejs中處理I/O操作中移動的數據時,就有可能使用Buffer庫。
簡單來說,buffer就是一個處理二進制數據的緩沖模塊,那和stream又有什么關系呢?
可以看下下面的圖:
這張圖里,可以把很大的一塊data進行肢解,然后儲存到buffer中,形成一個個的相對比較小的data chunk;
在這張圖里,chunk one by one向前傳遞就成了stream。
所以回到我們最初的問題,用readable stream和fs里的readFile有什么不同?
1、Readable streamreadFile是等一個file全部讀完之后才fire callback函數,進行下一步動作;而stream是通過把file里的數據分成很多很多個小的chunk, 每次callback函數感知到data chunk的時候就會觸發。這樣傳遞數據會更快。
var fs = require("fs"); var myReadStream = fs.createReadStream(__dirname + "/input.txt", "utf8"); //這里的‘utf8"如果不加的話會解碼成二進制(因為buffer) myReadStream.on("data", function(chunk){ console.log("new chunk received"); console.log(chunk); }); //stream也繼承eventEmitter //每次感知到data chunk就會觸發,不需要等到整個file都讀完2、Writable stream
//和readable stream類似 //會創造出來一個output.txt在目錄下 var fs = require("fs"); var myReadStream = fs.createReadStream(__dirname + "/input.txt", "utf8"); var myWriteStream = fs.createWriteStream(__dirname + "/output.txt"); myReadStream.on("data", function(chunk){ console.log("new chunk received"); myWriteStream.write(chunk); });3、pipe
因為把readable stream轉成writable stream在node.js里非常常見,所以有一個更elegant的辦法就是用pipe:
var fs = require("fs"); var myReadStream = fs.createReadStream(__dirname + "/input.txt", "utf8"); var myWriteStream = fs.createWriteStream(__dirname + "/output.txt"); //pipe只能從可讀流出發,不能從可寫流出發 myReadStream.pipe(myWriteStream);
如果加上web server就可以這么寫:
var fs = require("fs"); var http = require("http"); var server = http.createServer(function(req, res){ console.log("request was made: "+ req.url); res.writeHead(200, {"Content-Type": "text/plain"}); var myReadStream = fs.createReadStream(__dirname + "/input.txt", "utf8"); myReadStream.pipe(res); //response obj is writable }); server.listen(3000); console.log("listen to port 3000");
如果要傳遞的數據是html格式的話:
var fs = require("fs"); var http = require("http"); var server = http.createServer(function(req, res){ console.log("request was made: "+ req.url); //html格式也可以用stream傳遞,用pipe把可讀流轉成可寫流 res.writeHead(200, {"Content-Type": "text/html"}); var myReadStream = fs.createReadStream(__dirname + "/index.html", "utf8"); myReadStream.pipe(res); //response obj is writable }); server.listen(3000); console.log("listen to port 3000");
如果傳遞的數據是json的話:
//不使用stream,直接在res.end()里面傳遞 //但是要注意的是,end()里面只接受string,不能把object直接放進去 var fs = require("fs"); var http = require("http"); var server = http.createServer(function(req, res){ console.log("request was made: "+ req.url); res.writeHead(200, {"Content-Type": "application/json"}); var myobj = { name: "Ryu", job: "ninja", age: 29 }; res.end(JSON.stringify(myobj)); }); server.listen(3001); console.log("listen to port 3001");五、Router
介紹一個很簡單的router的使用辦法,只要用if判斷req.url,然后用stream寫入即可:
var http = require("http"); var fs = require("fs"); var server = http.createServer(function(req,res){ console.log("request was made: "+ req.url); if(req.url === "/home" || req.url === "/"){ res.writeHead(200, {"Content-Type" : "text/html"}); //用fs的pipe把readable stream改成writable stream fs.createReadStream(__dirname +"/index.html").pipe(res); }else if(req.url === "/sample"){ res.writeHead(200, {"Content-Type": "text/html"}); fs.createReadStream(__dirname + "/sample.html").pipe(res); }else if(req.url === "/api/ninjas"){ var ninjas = [{name: "ryu", age: 29}, {name: "yoshi",age:32 }]; res.writeHead(200, {"Content-Type": "application/json"}); res.end(JSON.stringify(ninjas)); } //其實還可以再寫一個404 page }); server.listen(3000); console.log("now listening to port 3000");
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82392.html
摘要:例如現在的入門學習手記系列。收到粉絲留言和打賞的喜悅。安裝上一篇入門學習手記一,主要是介紹了的核心概念,是整個學習過程的基礎知識。新生成的類似如下入門學習手記因為生成的內容過多,我直接省略掉了。 showImg(https://segmentfault.com/img/bVbk5Nd?w=1150&h=599); 本人微信公眾號:前端修煉之路,歡迎關注。 最近開始想要維護一個個人的公眾...
閱讀 666·2021-11-15 11:37
閱讀 4105·2021-09-09 09:34
閱讀 3559·2019-08-30 15:52
閱讀 2602·2019-08-29 14:03
閱讀 2842·2019-08-26 13:36
閱讀 1587·2019-08-26 12:16
閱讀 1592·2019-08-26 11:45
閱讀 3488·2019-08-23 18:41