一、node.js回调
node.js中使用了大量的回调函数,基本上每个Api都支持回调;使用回调函数最好的有点就在于可以使异步的操作尽量的同步化去处理,
二、node.js事件循环
node.js是单进程单线程的应用程序,但是因为v8提供的异步执行回调接口,通过这些异步的回调接口可以执行大量的并发,所以性能非常的高,
node.js的单线程类似于进入了一个while(true)的事件循环,知道没有事件观察者就退出,每个异步事件都生成一个事件观察者,如果有时间发生就调用该回调函数;
1、事件驱动程序
node.js采用事件驱动模型,当web-server接收到请求,就把它关闭然后进行处理,然后去服务下一个web-server请求。当这个请求完成,它被放回处理队列,当到达队列开头,这个结果就返回给用户。这个模型很高效而且可扩展性非常强,因为web-server一直接受请求而不进行等待任何的读写操作,,,这个事件驱动模型被称之为非阻塞式IO或者事件驱动IO。
node.js有多个内置的对象,可以通过引入events模块,并通过实例化EventEmitter类来绑定和监听事件。
例如 var events = require('events'); //引入events模块
var eventEmitter = new events.EventEmitter(); //创建eventEmitter对象
eventEmitter.on('connect',fn); //绑定connect 事件处理程序
function fn(){ console.log('监听事件')};
eventEmitter.emit(' connect '); //触发connect 事件
在node.js应用程序中,执行异步操作的函数将回调函数最为最后一个参数,回调函数接受错误对象为第一个参数。
2、eventEmitter
node.js所有的异步I/O操作在完成时,都会发送一个事件到事件队列。
node.js里的许多对象都会分发事件: 一个 net server 对象会在每次有新连接时触发一个事件, 一个fs。readStream对象会在文件被打开时触发一个事件。所有这些产生事件的对象都是event.EventEmitter的实例。
events模块只提供了一个对象,events.EventEmitter. eventsEventEmitter对象的核心就是事件触发和事件监听器的封装。
EventEmitter对象如果在实例化的过程中发生错误,就会触发error事件。 当添加新的监听器时,newListener事件会触发,当监听器被移除时,removeListener事件被触发。
EventEmitter对象的每一个事件由一个事件名和若干个事件参数组成,事件名是一个字符串,通常有一定的语意。 对于每个事件,EventEmitter支持若干个事件监听器;当事件被触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
方法:
1、addListener(event, listener);
2、 on(event, listener);
3、once(event, listener);
4、removeListener(event, listener)
5、removeAllListener([event])
6、setMaxListeners(n)
7、listeners(event)
8、emit(event, [arg1],[arg2])
error事件
EventEmitter定义了一个特殊的事件error,它包含了错误的语义,我们在遇到异常的时候通常会触发error事件。
当error 被触发时,EventEmitter规定如果没有响应的监听器,node.js会把它当做异常,退出程序并输出错误信息。我们一般要为会触发error事件的对象设置监听器,避免遇到错误后整个程序崩溃。
大多数时候我们不会直接使用EventEmitter,而是在对象中继承它。 包括fs、net、http在内的,只要支持事件响应的核心模块都是EventEmitter的子类。
三、node.js中的buffer(缓冲区)
javaScript语言自身只有字符串数据类型,没有二进制数据类型。但是在处理TCP流或文件流时,必须使用到二进制数据。因此在node.js中,定义了一个buffer类,该类用来创建一个专门存放二进制数据的缓存区。
在6.0之前创建Buffer对象直接使用new buffer()构造函数来创建对象实例,但是buffer对内存的权限操作相比很大,可以直接捕获到一些敏感信息,所以在v6.0以后,官方文档里面建议使用buffer.from()接口去创建buffer 对象。
1、buffer 与 字符编码
Buffer实例一般用于表示编码字符的实例,比如utf-8、ucs2、base64、或十六进制编码的数据。 通过使用显示的字符编码就可以在buffer实例与普通的javascript字符串之间进行相互转换。
node.js支持的字符串编码包括:
1): ascli: 仅支持7位的ASCII数据;
2): utf8: 多字节的unicode编码;
3): utf16le: 2或4个字节,小字节编码的Unicode字节;
4): ucs2: utf16le的别名;
5): base64
6): latin1: 一种把buffer编码成一字节编码的字符串的方式
7): binary: latin1的别名;
8): hex: 将每个字节编码为两个十六进制字符;
创建buffer 类: Buffer提供了一些Api来创建类,
比如: Buffer.alloc(size, file): 返回一个指定大小的buffer实例,如果没有设置file,则默认填满0;
Buffer.allocUnsafe(size): 返回一个指定大小的buffer实例,但是它不会被初始化,所以它可能包含敏感的数据;
Buffer.allocUnsafeSlow(size):
Buffer.from(array): 返回一个被array的值初始化的新的buffer实例(传入的array的元素必须是数字,否则会自动被0覆盖);
Buffer.form(arrayBuffer,[ byteOffset[,length]]): 返回一个新建的与给定的ArrayBuffer共享同一内存的buffer;
Buffer.from(buffer): 复制传入的buffer实例的数据,并返回一个新的Buffer实例;
Buffer.from(string[,encoding]): 返回一个被string的值初始化的新的Buffer实例;
例如:
创建一个包含[0x1, 0x2, 0x3]的buffer
Buffer.from([1, 2, 3])
创建一个包含utf-8字节的buffer
Buffer.from('test')
创建一个包含latin1字节的buffer
Buffer.from('test', 'latin1')
写入缓存区
buf.write(string, offset, length, encoding ); //string:写入缓存区的字符串; offset: 缓存区开始写入的索引值,默认为0 ;lenght: 写入的字节数,默认为buffer.length; encoding: 使用的编码。默认为utf-8;
buf = Buffer.alloc(256);
len = buf.write('www.baidu.com');
从缓存区读取数据
buf.tostring(encoding, start, end);
将buffer转化为json对象
buf.toJSON()
缓存区拼接
buf.concat[list, totalLength]; //list: 用于合并的buffer对象数组列表; totalLength: 指定合并后buffer数组的总长度;
缓存区比较
buf.compare(otherBuffer); //otherBuffer: 与buf进行比较的另外一个buffer;
拷贝缓存区
buf.copy(targeBuffer, targeStart, sourceStart, sourceEnd); //targeBuffer: 要拷贝的buffer对象; targeStart: 插入到哪里; sourceStart: 从哪开始拷贝; sourceEnd: 拷贝到哪里
缓存区裁剪
buf.slice(start, end); //start: 从哪开始裁剪, end: 裁剪到哪里,但不包括这个结束位置的
缓存区长度
buf.length;