Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。

以下简单实现:

function EventEmitter() {
this.events = {}
this.counts = 0
this.maxNum = 10
// 内置事件:newListener -> 事件在添加新监听器时被触发。removeListener -> 事件在接除监听器时被触发。
this.innerEvent = {
NEWLISTENER: 'newListener',
REMOVELISTENER: 'removeListener'
}
} // 为指定事件添加一个监听器到监听器数组的尾部。
function addListener(eventName, callback) {
if (typeof callback !== 'function') return if (!this.events[eventName]) {
if (!this._isInnerEvent(eventName)) {
this.events[eventName] = [{ type: 'on', callback }]
this.counts++
if (this.counts > this.maxNum) {
console.warn(`目前监听器数量:${this.counts}个,监听器已经超过${this.maxNum}个`)
}
if (this.events[this.innerEvent.NEWLISTENER]) {
this.emit(this.innerEvent.NEWLISTENER, eventName)
}
} else {
this.events[eventName] = { type: 'on', callback }
}
} else {
this.events[eventName].push({ type: 'on', callback })
}
} EventEmitter.prototype = {
_toString: function (obj) {
return Object.prototype.toString.call(obj).slice(8, -1)
}, _isInnerEvent: function (eventName) {
return !!this.innerEvent[eventName.toUpperCase()]
}, addListener: addListener,
on: addListener, // 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
emit: function () {
let arg = Array.prototype.slice.call(arguments)
let eventName = arg[0]
let params = arg.slice(1) if (!this._isInnerEvent(eventName)) {
if (this._toString(this.events[eventName]) === 'Array' && this.events[eventName].length) {
this.events[eventName].forEach(event => {
let { type, callback } = event
callback.apply(null, params)
if (type === 'once') {
this.events[evtName].splice(index, 1)
}
})
return true
}
return false
} else {
this.events[eventName].callback.apply(null, params)
if (this.events[eventName].type === 'once') {
delete this.events[eventName]
}
}
}, // 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
once: function (eventName, callback) {
if (typeof callback !== 'function') return if (!this.events[eventName]) {
if (!this._isInnerEvent(eventName)) {
this.events[eventName] = [{ type: 'once', callback }]
this.counts++
if (this.counts > this.maxNum) {
console.warn(`目前监听器数量:${this.counts}个,监听器已经超过${this.maxNum}个`)
}
if (this.events[this.innerEvent.NEWLISTENER]) {
this.emit(this.innerEvent.NEWLISTENER, eventName)
}
} else {
this.events[eventName] = { type: 'once', callback }
}
} else {
this.events[eventName].push({ type: 'once', callback })
}
}, // 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。
removeListener: function (eventName, callback) {
if (this._toString(this.events[eventName]) === 'Array') {
let _events = this.events[eventName].concat() for (let i = 0; i < _events.length; i++) {
if (_events[i].callback === callback) {
this.events[eventName].splice(i, 1)
return
}
}
}
}, // 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
removeAllListeners: function (eventName) {
if (eventName) {
if (this.events[eventName]) {
delete this.events[eventName]
if (!this._isInnerEvent(eventName)) {
this.counts--
if (this.events[this.innerEvent.REMOVELISTENER]) {
this.emit(this.innerEvent.REMOVELISTENER, eventName)
}
}
}
} else {
this.events = {}
this.counts = 0
}
}, // 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。
setMaxListeners: function (num) {
this.maxNum = num
}, // 返回指定事件的监听器数组。
listeners: function (eventName) {
if (this._toString(this.events[eventName]) === 'Array') {
let _events = this.events[eventName].concat()
let newArray = []
_events.forEach(item => {
newArray.push(item.callback)
})
return newArray
}
}, // 返回指定事件的监听器数量
listenerCount: function (eventName) {
if (this._toString(this.events[eventName]) === 'Array') {
return this.events[eventName].length
}
}
} var eventEmit = new EventEmitter() eventEmit.on('newListener', function newListener(eventName) {
console.log('>>>>newListener ---', eventName)
})
eventEmit.on('removeListener', function removeListener(eventName) {
console.log('>>>>removeListener ---', eventName)
}) console.log(eventEmit) function event1() {
console.log('event1')
}
eventEmit.on('event', event1) eventEmit.on('event1', event1) eventEmit.on('event', function event2() {
console.log('event2')
}) eventEmit.emit('event')
eventEmit.emit('event1')

nodejs之EventEmitter实现的更多相关文章

  1. nodejs基础 -- EventEmitter

    var events = require('events'); nodejs所有的异步I/O操作在完成时都会发送一个事件到事件队列 nodejs里面的许多对象都会分发事件,如: 一个net.Serve ...

  2. nodejs中EventEmitter

    在模块events中,定义了一个EventEmitter类,可以使用var EventEmitter = require('events');访问它.基本上所有发送事件的对象都是继承自EventEmi ...

  3. nodejs 事件EventEmitter

    index.js: // 引入 events 模块 var events = require('events'); //处理函数要写在调用前 var eventHandler = function() ...

  4. 深入浅出NodeJS——数据通信,NET模块运行机制

    互联网的运作,最根本的驱动就是信息的交互,NodeJS 在数据交互这一块做的很带感,异步编程让人很惬意,关于 NodeJS 的数据通信,最基础的两个模块是 NET 和 HTTP,前者是基于 TCP 的 ...

  5. 深入理解nodejs的异步IO与事件模块机制

    node为什么要使用异步I/O 异步I/O的技术方案:轮询技术 node的异步I/O nodejs事件环 一.node为什么要使用异步I/O 异步最先诞生于操作系统的底层,在底层系统中,异步通过信号量 ...

  6. backbone event 事件订阅 和发布 源码小读

    nodejs有eventEmitter 类,想到backbone  有个event模块 可以对对象做事件绑定和触发,是backbone的核心模块. backbone event模块 on 添加自定义事 ...

  7. webpack-插件机制杂记

    系列文章 Webpack系列-第一篇基础杂记 webpack系列-插件机制杂记 前言 webpack本身并不难,他所完成的各种复杂炫酷的功能都依赖于他的插件机制.或许我们在日常的开发需求中并不需要自己 ...

  8. [转] webpack之plugin内部运行机制

    简介 webpack作为当前最为流行的模块打包工具,几乎所有的主流前端开发框架(React.Vue等)都会将其作为默认的模块加载和打包工具.通过简单的配置项,使用各种相关的loader和plugin, ...

  9. .12-浅析webpack源码之NodeWatchFileSystem模块总览

    剩下一个watch模块,这个模块比较深,先大概过一下整体涉及内容再分部讲解. 流程图如下: NodeWatchFileSystem const Watchpack = require("wa ...

随机推荐

  1. 【JMeter_18】JMeter逻辑控制器__吞吐量控制器<Throughput Controller>

    吞吐量控制器<Throughput Controller> 业务逻辑: 他的实际作用似乎跟吞吐量扯不上什么关系.就是单纯的控制控制器下的子节点被执行的次数或被执行比列,该控制器默认为多线程 ...

  2. Redis 数据结构 之 SDS

    SDS(simple dynamic string),简单动态字符串.s同时它被称为 Hacking String.hack 的地方就在 sds 保存了字符串的长度以及剩余空间.sds 的实现在 sd ...

  3. Spring Boot 2 实战:利用Redis的Geo功能实现查找附近的位置

    1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...

  4. redis概要学习

    redis 概要学习 redis简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Re ...

  5. WeChair项目Alpha冲刺(4/10)

    团队项目进行情况 1.昨日进展    Alpha冲刺第四天 昨日进展: 前端完成小程序登录态的定义 LoginController编写初步完成同时修改并更新了代码,但是在将编码好的项目部署到服务器上时 ...

  6. Python-argparse模块-获取命令行参数

    #!/usr/bin/python3 """ Author : Jet Bi License : www.cyeap.com Summary : 获取命令行的参数 Not ...

  7. 一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了

    自从2019年11月我们出版了<千金良方--MySQL 性能优化金字塔法则>一书之后,持续不断有人来询问我MySQL 4 个系统字典库相关的问题,因为篇幅原因,书中并没有完整收录4个字典库 ...

  8. 入门大数据---Hbase是什么?

    一.Hbase是什么? Hbase属于NoSql的一种. NoSql数据库分为如下几类: Key-Value类型数据库 这类数据库主要会使用到一个哈希表,这个表有一个特定的键和一个指针指向特定的数据. ...

  9. Illegal reflective access by org.apache.hadoop.security.authentication.util.KerberosUtil

    在使用Java API操作HBase时抛出如下异常: Illegal reflective access by org.apache.hadoop.security.authentication.ut ...

  10. .netcore项目codefirst时使用的配置文件是appsettings.json

    .netcore项目创建完毕后,会发现项目中有好几个配置文件: appsettings.json appsettings.Development.json appsettings.Production ...