首页 > 代码库 > nodejs(二) --- 重要知识点回顾
nodejs(二) --- 重要知识点回顾
1. 运行一个nodejs文件,
如一个js文件中只含有console.log("hello world");的文件,我们再git里运行node,即 node hello.js 即可发送输出hello world。如下:
2. 交互模式
直接输入node,即进入node环境,即可输入任何语句:
3. 创建一个简单的服务器:
创建server.js -> require http模块 -> 调用 createServer 方法进行创建 -> 监听某个端口 -> 运行js文件(实际上是在运行这个node服务器) -> 在浏览器中发送请求。
js文件如下:
其中比较重要的是要知道createServer这个内置函数就是用于创建服务器的,然后接受一个函数作为参数,我们可以用writeHead方法来写头部,使用end方法来输出内容。用listen来监听端口号。当然,也可以是监听8889等端口号,只要是合法的就行。在浏览器端发出请求,结果如下:
4. node中的npm:
安装node时就已经安装了npm,即一个包管理工具,我们一般利用它来安装一些包,即npm install <package> 如果后面添加 -g ,那么就会将包安全到全局环境,即user路径下。如果不添加,就会安装在当前文件夹下,当然首先会创建node_modules文件,在此之下。
一般,我们要创建一个项目时,我们可以先npm init,通过它,我们就可以创建一个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 <package>
更新模块: npm update <package>
版本号相关: 当使用npm下载和发布代码时,都会涉及到版本号相关,即X-Y-Z,一般而言,只有当版本发生了重大的变化,不向下兼容时,X才会变化; 如果增加了新的功能,仍旧向下兼容 Y 发生变化; 如果仅仅是做了很小的改变,如修复了bug,那么 Z 发生变化。
如果希望知道某条命令的详细信息,如install的,可以输入 npm help install
npm连接的是国外的网站,也可以使用淘宝镜像:
npm install -g cnpm --registry=https://registry.npm.taobao.org
然后就可以使用cnpm来安装了。
5. nodejs REPL
即node的交互式解释器,即我们输入node之后即进入node环境,这个node环境就是node的交互式解释器。
值得注意的是,和console控制台不同,REPL支持多行输入,如下所示:
$ node> var x = 0undefined> do {... x++;... console.log("x: " + x);... } while ( x < 5 );x: 1x: 2x: 3x: 4x: 5undefined>
一般我们使用ctrl + c来退出该环境,大多数情况下,我们都是用ctrl+c来退出环境的。不论是否是node。
6. nodejs回调函数
在node中,我们知道其最大的特点就是异步I/O,而实现异步I/O的关键就在于回调函数。
首先,我们看看同步的是什么样:
var fs = require("fs");var data = http://www.mamicode.com/fs.readFileSync(‘test.txt‘);console.log(data.toString());console.log("over");
这是main.js中的代码,即先引入fs模块,然后才能实用相应的API,readFileAsync()函数用于同步读取文件,它是阻塞的,返回这个读取的文件,输出如下:
下面这个一个异步的,
var fs = require("fs"); fs.readFile("test.txt",function (err, data) { if (err) { console.log(err); } else { console.log(data.toString()); } }); console.log("over");
结果如下:
即readFile是一个异步的,在执行这条语句的时候不会阻塞后面的语句,而是在读完文件之后再console。
即我们在读取代码的时候可以做下面的很多事情,这样就可以节省很多时间。
注意node是单进程和单线程的,所以这里怎么理解呢?
7. nodejs事件循环
nodejs事件循环利用的是观察者模式,也就是发布订阅模式。简单的理解,DOM元素绑定事件就是这样的模式。其中绑定的元素是发布者,函数是订阅者,当元素发生了变化时(被点击等),就会通知所有的订阅者。
nodejs使用事件驱动模型,当服务器接受到了请求之后,就会关闭这个请求,然后再处理,为的是等待下一个请求。这样,请求就不会被耽搁。这个模型的效率非常高,因为他一直在接受请求,而没有等待任何读写操作。在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数:
虽然这里没有所谓的DOM元素,但是实现应当是一样的,即观察者模式的最好理解是好莱坞电影中的一句话: 你不要打电话给我,我会打电话给你。
在node中我们常常使用events模块来实现,即首先引入events,然后创建一个对象,利用这个对象的on方法绑定时间,利用对象的emit方法来触发事件,如下所示:
var events = require("events");var eventEmitter = 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");
最终效果如下:
在这里,我们就可以认为这是发布订阅者模式,首先可以知道发布者是selfDefine事件,订阅者是4个,一旦selfDefine被触发,那么就会通知订阅者,方法是将订阅者添加到了Event Loop中去,然后通过事件循环来监听,一旦被触发,就会通知,即我给你打电话,你没有给我打电话。
当事件触发时,注册到这个事件的事件监听器被依次调用。
另外,在on和emit中是可以传递参数的,如下所示:
var events = require("events");var eventEmitter = 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是类似的,都是添加某一个事件的监听器。
removeListener(event, listener) --- 即通过此API可以将监听器取消(特定的listener)。
removeAllListeners(event) --- 可以取消event下的所有监听器。
newListener(event, listener); --- 该事件在添加新的监听器时被触发。
listenerCount(emitter, event); --- 返回指定监听器的数量。
listeners(event) --- 返回指定事件的监听器数组。
once(event, listener) --- 通过once就可以知道,这个监听器只会监听一次,后面再调用,就不会监听了。
举例如下:
var events = require("events");var eventEmitter = 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);
最终的执行效果如下:
在执行过程中vai on和via once是同时出现的,过了1s之后,via on 出现, via once不再出现,因为通过once添加的监听器只会监听一次,然后就被销毁了(即后面不再监听)。
8. Nodejs Buffer (缓冲区)
作为服务器端语言的nodejs,自然会接受请求,如TCP请求,都是通过二进制来传递的,但是js语言本身并没有接受二进制的api,所以nodejs中添加了Buffer类来作为存储二进制数据的缓冲区。
通过Buffer类创建buffer实例的几种方法:
1. 创建长度为10字节(1 B = 8 bit)的Buffer类, var buf = new Buffer(10);
2. 通过数组创建Buffer实例, var buf = new Buffer([10, 20, 30, 15]);
3. 通过一个字符串来创建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是缓冲区开始写入的索引值,默认为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对象。其中list是一个数组,其中的每个元素是一个buffer实例,totalLength是在制定合并之后的总长度。
- buf.compare(otherBuffer) (缓冲区大小比较) --- 比较两个缓冲区的大小,返回 0 -1 1 。
- buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]]) (缓冲区的拷贝)
- buf.slice([start[, end]])(缓冲区的裁剪)
- buf.length() --- 返回缓冲区的长度。
- ......
9. Nodejs Stream(流)
nodejs(二) --- 重要知识点回顾