用事件发射器处理重复性事件
事件发射器示例
echo 服务器就是一个处理重复性事件的简单例子,当你给它发送数据时,它会把数据发回来。
//echo_server.js
const net = require('net');
const server = net.createServer(socket=>{
socket.on('data',data=>{//当读取到新数据时处理data事件
socket.write(data);//把数据写回客户端
});
});
server.listen(8888);
启动程序后可以通过telnet进行访问。对于未启用telnet服务可参见win10如何安装telnet服务
Ctrl+C可结束程序!
响应只应该发生一次的事件
const net = require('net');
const server = net.createServer(socket => {
socket.once('data', data => {//data事件只处理一次
socket.write(data);
});
});
server.listen(8888);
创建事件发射器:一个 PUB/SUB 的例子
事件名称 事件是可以具有任意字符串值的键: data、 join 或某些长的让人发疯的事件名都行。只有一个事件是特殊的,那就是 error。
//telchannel.js
//用 EventEmitter 实现自己的发布/预订逻辑,做一个通信通道。
const events = require('events');
const net = require('net');
const channel = new events.EventEmitter();
channel.clients = {};
channel.subscriptions = {};
channel.on('join',function(id,client){
//添加join事件的监听器,保存用户的client对象
this.clients[id] = client;
this.subscriptions[id] = (senderId,message)=>{
if(id!=senderId){//忽略发送者
this.clients[id].write(message);
}
};
//添加一个专门针对当前用户的broadcast事件监听器
this.on('broadcast',this.subscriptions[id]);
});
const server = net.createServer(client=>{
const id = `${client.remoteAddress}:${client.remotePort}`;
//当有用户连接时发出join事件,指明用户ID和client对象
channel.emit('join',id,client);
client.on('data',data=>{
data = data.toString();
//当有用户发送数据时,发出一个频道broadcast事件,指明用户id信息
channel.emit('broadcast',id,data);
});
});
server.listen(8888);
在用户关闭连接离开聊天室后,原来那个监听器还在,仍会尝试向已经断开的连接写数据就会出错。为了解决这个问题,还要按照下面的代码清单把监听器添加到频道事件发射器上,并且向服务器的 close 事件监听器中添加发射频道的leave 事件的处理逻辑。leave 事件本质上就是要移除原来给客户端添加的 broadcast 监听器。
//telchannel.js
//用 EventEmitter 实现自己的发布/预订逻辑,做一个通信通道。
const events = require('events');
const net = require('net');
const channel = new events.EventEmitter();
channel.clients = {};
channel.subscriptions = {};
channel.on('join',function(id,client){
const welcome =
`Welcom!Guests online:${this.listeners('broadcast').length}`;
client.write(`${welcome}\n`);
//添加join事件的监听器,保存用户的client对象
this.clients[id] = client;
this.subscriptions[id] = (senderId,message)=>{
if(id!=senderId){//忽略发送者
this.clients[id].write(message);
}
};
//添加一个专门针对当前用户的broadcast事件监听器
this.on('broadcast',this.subscriptions[id]);
});
channel.on('leave',function(id){
//leave事件的监听器
channel.removeListener('broadcast',this.subscriptions[id]);
//移除指定客户端的broadcast监听器
channel.emit('broadcast',id,`${id} has left.\n`);
});
channel.on('shutdown',()=>{
channel.emit('broadcast','','The server has shut down.\n');
channel.removeAllListeners('broadcast');
});
const server = net.createServer(client=>{
const id = `${client.remoteAddress}:${client.remotePort}`;
//当有用户连接时发出join事件,指明用户ID和client对象
channel.emit('join',id,client);
client.on('data',data=>{
data = data.toString();
if(data==='shutdown\r\n'){
channel.emit('shutdown');
}
//当有用户发送数据时,发出一个频道broadcast事件,指明用户id信息
channel.emit('broadcast',id,data);
});
client.on('close',()=>{
//当用户断开时发出leave事件
channel.emit('leave',id);
});
});
server.listen(8888);
此处shutdown不好使,怀疑为在传输data时'shutdown'被按字母依次发送's','h'故不能检测到。