卖坚果的怪叔叔 卖坚果的怪叔叔
  • 首页
  • 生活
  • 技术
  • 记录
  • 工具箱
  • 关于我
首页 › 技术 › Node.js EventEmitter 和 Buffer

Node.js EventEmitter 和 Buffer

坚果大叔
2019-05-19 17:54:28技术阅读 2,398

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。Node.js 中许多对象都会分发事件。一个net.Server对象会在每次有新连接时触发一个事件,而另外一个 fs.readStream对象会在文件被打开的时候触发一个事件,所有的这些产生的事件对象都是 events.EventEmitter的实例。

EventEmitter 类

events 模块只提供了一个对象:events.EventEmitter。events.EventEmitter的核心就是事件触发和事件监听器功能的封装。你可以通过 require('events')来使用该模块,如下:

// 引入 events 模块
var events = require('events');

// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

EventEmitter对象如果在实例化的时候发生错误,将会触发 error 事件。当添加新的监听器的时候,newListener事件会被触发,当该监听器被移除的时候,removeListener 将会被触发。

案例:

//event.js 文件
var EventEmitter = require('events').EventEmitter; 
var event = new EventEmitter(); 
event.on('some_event', function() { 
    console.log('1s后 some_event 事件触发'); 
}); 
setTimeout(function() { 
    event.emit('some_event'); 
}, 1000); 

// node event.js
// 1s 后执行 

EventEmitter 的每个事件由一个 事件名 和 若干个 参数 组成,事件名是一个字符串,通常表达一个的意思,对于每个事件,EventEmitter支持多个事件监听器。当事件触发的时候,注册到这个事件上的事件监听器将依次被调用,事件参数作为回调函数参数传递。如下:

 // event.js 文件
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); 

// node event.js
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数

在上面例子中,emitter为事件someEvent注册了两个事件监听器,然后触发了someEvent事件,从运行结果中可以看到 两个事件监听器的回调函数 先后被调用。

EventEmitter提供了多个属性,如 on 和 emit 。 on 函数用来绑定事件函数,emit 用来触发一个事件,具体参数如下:

参数名 描述
addListener(event, listener) 为指定事件添加一个监听器到监听器数组的尾部
on(event, listener) 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数
once(event, listener) 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器
removeListener(event, listener) 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。它接受两个参数,第一个是事件名称,第二个是回调函数名称
removeAllListeners([event]) 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器
setMaxListeners(n) 用于提高监听器的默认限制的数量
listeners(event) 返回指定事件的监听器数组
emit(event, [arg1], [arg2], [...]) 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false
listenerCount(emitter, event) 返回指定事件的监听器数量
newListener 该事件在添加新监听器时被触发
removeListener 当指定监听器被删除的时候触发,注意:该触发器之后的监听器

实例:

var events = require('events');
var eventEmitter = new events.EventEmitter();

// 监听器 #1
var listener1 = function listener1() {
   console.log('监听器 listener1 执行。');
}

// 监听器 #2
var listener2 = function listener2() {
  console.log('监听器 listener2 执行。');
}

// 绑定 connection 事件,处理函数为 listener1 
eventEmitter.addListener('connection', listener1);

// 绑定 connection 事件,处理函数为 listener2
eventEmitter.on('connection', listener2);

var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 个监听器监听连接事件。");

// 处理 connection 事件 
eventEmitter.emit('connection');

// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受监听。");

// 触发连接事件
eventEmitter.emit('connection');

eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 个监听器监听连接事件。");

console.log("程序执行完毕。");


// 执行结果:

$ node main.js
2 个监听器监听连接事件。
监听器 listener1 执行。
监听器 listener2 执行。
listener1 不再受监听。
监听器 listener2 执行。
1 个监听器监听连接事件。
程序执行完毕

执行error事件,当error被触发的时候,EventEmitter 规定如果没有响应的监听器,那么node.js就将它当作异常,退出程序并输出错误信息。所以我们要为error设置监听器,避免因为错误导致程序崩溃。如下:

var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.emit('error'); 

大多数时候不会在node中直接使用EventEmitter,而是在对象中继承去使用它,例如 fs、net、http等,只要是支持事件响应的核心模块都是EventEmitter的子类这样做的原因有两点,如下:

1、具有某个实体功能的对象实现事件符合语义,事件的监听和发生应该是一个对象的方法

2、另外,因为JavaScript的对象机制是基于原型的,支持部分多重继承,继承EventEmitter不会打乱对象原有的继承关系

因为JavaScript只有字符串数据类型没有二进制数据类型。但是在处理TCP流或文件流时,必须使用二进制数据。所以在node.js定义了一个Buffer类,该类用来创建一个专门存放二进制数据的缓存区。

在node.js中,Buffer类是随Node内核一起发布的核心库,Buffer库可以让nodejs处理二进制数据,一个Buffer类似一个整数数组。

Buffer实例一般用于表示编码字符的序列,比如 UTF-8, Base64, 或十六进制编码的数据,通过使用显示的字符编码,就可以在Buffer实例与普通的JavaScript字符串之间进行相互转换。如下:

const buf = Buffer.from('runoob', 'ascii');

// 输出 72756e6f6f62
console.log(buf.toString('hex'));

// 输出 cnVub29i
console.log(buf.toString('base64'));

nodejs支持的字符编码:

ascii -- 仅支持7位ASCII数据
utf8 -- 多字节编码的Unicode字符
utf16le -- 2 或 4 个字节
ucs2
base64
latin1
binary
hex

Buffer提供下面多个api来创建Buffer类

Api类名 说明
Buffer.alloc(size[, fill[, encoding]]) 返回一个指定大小的 Buffer 实例
Buffer.allocUnsafe(size) 返回一个指定大小的 Buffer 实例
Buffer.allocUnsafeSlow(size)
Buffer.from(array) 返回一个被 array 的值初始化的新的 Buffer 实例
Buffer.from(arrayBuffer[, byteOffset[, length]]) 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer
Buffer.from(buffer) 复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例
Buffer.from(string[, encoding]) 返回一个被 string 的值初始化的新的 Buffer 实例

案例:

// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);

// 创建一个长度为 10、且用 0x1 填充的 Buffer。 
const buf2 = Buffer.alloc(10, 1);

// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);

// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);

// 创建一个包含 UTF-8 字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');

// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');

语法:

写入node缓冲区的语法如下:

bur.write(string[, offset[, length]][, encoding])

参数:

string - 写入缓冲区的字符串
offset - 缓冲区开始写入的索引值,默认为0
length - 写入的字节数,默认为buffer.length
encoding - 使用的编码,默认 ‘utf8’

根据encoding的字符编码写入 string 到 buf中 offset位置,length参数是写入的字节数,如果buf没有足够的空间保存整个字符串,那么只会写入string的一部分,只部分解码的字符不会被写入。

返回值:
返回值实际写入的大小,如果buffer空间不足,则只会写入部分字符串

实例

buf = Buffer.alloc(256);
len = buf.write("www.runoob.com");

console.log("写入字节数 : "+  len);

// 结果

$node main.js
写入字节数 : 14

语法:

buf.toString([encoding[, start[, end]]])

参数:

encoding - 使用的编码
start - 指定开始读取的索引位置
end - 结束位置,默认为缓冲区的末尾

返回值:
解码缓冲区数据并使用指定的编码返回字符串

实例:

buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
  buf[i] = i + 97;
}


console.log( buf.toString('ascii'));       // 输出: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5));   // 输出: abcde
console.log( buf.toString('utf8',0,5));    // 输出: abcde
console.log( buf.toString(undefined,0,5)); // 使用 'utf8' 编码, 并输出: abcde

// 结果

$ node main.js
abcdefghijklmnopqrstuvwxyz
abcde
abcde
abcde

语法:

buf.toJSON()

注意:当字符串化一个 Buffer 实例时,JSON.stringify()会隐式地调用该toJSON()

返回值:
返回JSON对象

实例:

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);

// 输出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);

const copy = JSON.parse(json, (key, value) => {
  return value && value.type === 'Buffer' ?
    Buffer.from(value.data) :
    value;
});

// 输出: <Buffer 01 02 03 04 05>
console.log(copy);

// 结果

{"type":"Buffer","data":[1,2,3,4,5]}
<Buffer 01 02 03 04 05>

语法:

Buffer.concat(list[, totalLength])

参数:

list - 用于合并的 Buffer 对象数组列表
totalLength - 指定合并后 Buffer 对象的总长度

返回值:

返回一个多个成员合并的新 Buffer 对象。

实例:

var buffer1 = Buffer.from(('1'));
var buffer2 = Buffer.from(('2'));
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log("gogo 内容: " + buffer3.toString());

// 结果

gogo 内容: 12

语法:

buf.compare(otherBuffer)

参数:

ohterBuffer - 与 buf 对象比较的另外一个 Buffer 对象

返回值:

返回一个数字,表示 buf 在 otherBuffer 之前,之后或相同

实例:

var buffer1 = Buffer.from('ABC');
var buffer2 = Buffer.from('ABCD');
var result = buffer1.compare(buffer2);

if(result < 0) {
   console.log(buffer1 + " 在 " + buffer2 + "之前");
}else if(result == 0){
   console.log(buffer1 + " 与 " + buffer2 + "相同");
}else {
   console.log(buffer1 + " 在 " + buffer2 + "之后");

// 结果

ABC在ABCD之前

语法:

buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])

参数:

targetBuffer - 要拷贝的Buffer对象
targetStart - 数字,默认 0
sourceStart - 数字,默认 0
sourceEnd - 数字,默认: buffer.length

实例:

var buf1 = Buffer.from('abcdefghijkl');
var buf2 = Buffer.from('RUNOOB');

//将 buf2 插入到 buf1 指定位置上
buf2.copy(buf1, 2);

console.log(buf1.toString());

// 结果

abRUNOOBijkl

buf.slice([start[, end]])

参数:

start - 数字 可选,默认 0 
end - 数字 可选 默认: buffer.length

返回值:

返回一个新的缓冲区,它和旧缓冲区指向同一块内存,但是从索引 start 到 end 的位置剪切。

实例:

var buffer1 = Buffer.from('cui');
// 剪切缓冲区
var buffer2 = buffer1.slice(0,2);
console.log("buffer2 content: " + buffer2.toString());

// 结果

buffer2 content: cu

语法:

buf.length

返回值:
返回 Buffer 对象所占据的内存长度

实例:

var buffer = Buffer.from('1');
//  缓冲区长度
console.log("buffer length: " + buffer.length);

// 结果
buffer length: 1

Buffer EventEmitter
赞赏 赞(0)
本文系作者 @坚果大叔 原创发布在 卖坚果的怪叔叔。未经许可,禁止转载。
ES6入门之数组的扩展
上一篇
ES6入门之对象的新增方法
下一篇
在小程序中查看

这是个😊,挣点服务器费用😜

热门文章
猫?
Windows微信多开+防撤回!
deep 不生效!
重学JavaScript之匿名函数
如何激活Windows10?
Vue Print-js 打印问题记录~
专题标签
agent (1) CSS (15) dom (1) Es6入门系列 (14) Git (3) html (1) iview (1) JavaScript (9) js (4) Lif (1) Node (4) pyecharts (1) Python (10) ref (1) scriptable (1) Skill (1) vsCode (1) vue (4) wordpress (2) 三月 (1) 上海 (1) 假期 (1) 其他分享 (3) 前端两三问 (15) 古镇 (1) 外滩 (1) 对象 (1) 小程序 (5) 年度总结 (6) 年终总结 (1) 微信机器人 (4) 打字机 (1) 技术 (1) 日常问题 (8) 日常问题记录 (1) 春天 (2) 服务器 (2) 海族馆 (1) 生活 (8) 网上国网 (1) 记录 (3) 通勤 (1) 重学JavaScript (11) 面试题 (10) 🌸 (1)
什么是Agent?
2026-08-15 23:49:12
429 0 2
什么是 Skill?
2026-08-12 21:32:42
348 1 0
失业在家,我给小朋友做了一个练字小程序!
2026-08-07 16:21:52
690 10 1
上线8年,15万用户的小程序,一共赚了多少钱?
2026-05-30 18:01:24
4,683 4 0
  • 0
博主

一位佛系的前端开发者,略通摄影,乐于尝试新事物,热衷于美食。

友链
故事胶片
公众号
坚果大叔 执行上下文 卖坚果的怪叔叔 Dacking
Copyright © 2017-2026 卖坚果的怪叔叔

开往-友链接力

萌ICP备20230818号

苏ICP备18048410号-3
  • 首页
  • 生活
  • 技术
  • 记录
  • 工具箱
  • 关于我
# CSS # # JavaScript # # vue # # 微信 # # 生活 #
坚果大叔
345
文章
171
评论
432
喜欢