摘要:的介绍一般是这样在中,类是随内核一起发布的核心库。库为带来了一种存储原始数据的方法,可以让处理二进制数据,每当需要在中处理操作中移动的数据时,就有可能使用库。这样传递数据会更快。
零、开始之前 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");
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/82392.html
摘要:例如现在的入门学习手记系列。收到粉丝留言和打赏的喜悦。安装上一篇入门学习手记一,主要是介绍了的核心概念,是整个学习过程的基础知识。新生成的类似如下入门学习手记因为生成的内容过多,我直接省略掉了。 showImg(https://segmentfault.com/img/bVbk5Nd?w=1150&h=599); 本人微信公众号:前端修炼之路,欢迎关注。 最近开始想要维护一个个人的公众...
阅读 665·2021-11-15 11:37
阅读 4105·2021-09-09 09:34
阅读 3558·2019-08-30 15:52
阅读 2601·2019-08-29 14:03
阅读 2841·2019-08-26 13:36
阅读 1586·2019-08-26 12:16
阅读 1592·2019-08-26 11:45
阅读 3487·2019-08-23 18:41