events 的基本概念
我们知道,node 是一种非阻塞式 I/O 的模型,它的特点是事件驱动,所以 node 中有个非常典型的核心模块,这个模块非常常用,叫 events,它是一个类,里面主要实现了发布订阅的功能。
// 核心模块,可以直接引用的模块,不需要下载包或者自己写
const EventEmitter = require('events');
// 发布订阅 -> on 订阅 emit 发布 off 取消订阅
const events = new EventEmitter();
模块的订阅发布(on、emit)
events.on('女孩失恋了', function(data) {
console.log('哭', data);
});
events.on('女孩失恋了', function(data) {
console.log('吃', data);
});
events.emit('女孩失恋了', '她不够可爱');
// 哭 她不够可爱
// 吃 她不够可爱
process.nextTick 的使用场景
如果我想注册上,马上就触发怎么办,上 process.nextTick ~
// nextTick 可以解决异步调用的问题,而且方式优于 promise.then
process.nextTick(() => {
events.emit('女孩失恋了', '她不够可爱');
});
events.on('女孩失恋了', function(data) {
console.log('哭', data);
});
events.on('女孩失恋了', function(data) {
console.log('吃', data);
});
off 取消订阅
我们可以使用 off 取消订阅
const cry = function(data) {
console.log('哭', data);
}
events.on('女孩失恋了', cry);
// 必须传入事件名 + 回调方法名
events.off('女孩失恋了', cry);
once 绑定一次
events.on('女孩失恋了', function(data) {
console.log('吃', data);
});
events.once('女孩失恋了', function(data) {
console.log('逛街', data);
});
events.emit('女孩失恋了', '触发第一次');
events.emit('女孩失恋了', '触发第二次');
// 吃 触发第一次
// 逛街 触发第一次
// 吃 触发第二次
手动实现 events 模块的 on off once emit
// 手动实现 events 模块的 on off once emit
function EventEmitter() {
this._events = {};
}
EventEmitter.prototype.on = function(eventName, cb) {
// 考虑继承的情况,this 上如果没有 _events,手动创建
if (!this._events) this._events = {};
const callbacks = this._events[eventName] || [];
callbacks.push(cb);
this._events[eventName] = callbacks;
}
EventEmitter.prototype.emit = function(eventName, ...args) {
// 考虑继承的情况,this 上如果没有 _events,手动创建
const callbacks = this._events[eventName];
if (callbacks) {
callbacks.forEach(cb => cb(...args));
}
}
EventEmitter.prototype.off = function(eventName, cb) {
// 考虑继承的情况,this 上如果没有 _events,手动创建
if (!this._events) this._events = {};
if ( this._events[eventName]) {
this._events[eventName] = this._events[eventName].filter(fn => {
return fn !== cb && fn.l !== cb;
});
}
}
EventEmitter.prototype.once = function(eventName, cb) {
// 重写原 cb 方法
const one = (...args) => {
cb(...args);
// 执行完毕就删除订阅
this.off(eventName, one);
}
// 为了能 off 掉 once 订阅的事件 这里建立映射关系
// 因为 once 绑定的是 one 函数,而不是 cb
one.l = cb;
// 先绑定 这里不能通过 bind(this) 去重写 one 方法中的 this
// bind(this) 每次返回的是一个新函数
this.on(eventName, one);
}
module.exports = EventEmitter;
// 测试代码
// 核心模块,可以直接引用的模块,不需要下载包或者自己写
const EventEmitter = require('./events');
// 发布订阅 -> on 订阅 emit 发布
const events = new EventEmitter();
const eat = function(data) {
console.log('吃', data);
}
events.on('女孩失恋了', eat);
events.off('女孩失恋了', eat);
events.once('女孩失恋了', eat);
events.off('女孩失恋了', eat);
events.once('女孩失恋了', function(data) {
console.log('逛街', data);
});
events.emit('女孩失恋了', '触发第一次');
events.emit('女孩失恋了', '触发第二次');