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. 阿里云用smtp无法发送邮件

    无法发送邮件是因为什么网络协议的要求必须要封掉25端口,而这个解封的话弄了很长时间也没有弄开,所以就换了别的方法 这个的话我这块用的是PHPMailer 然后我把这个PHPMailer的配置文件里的 ...

  2. 上海开发票/v电13543443967

    关于事项:Iㄋ5一★4З44一★ㄋ9.б7开发票的准备资料必须要公司名称个人的话就用个人名字和身份证去税务柜台申请办理!公司的话要提供公司全称就是营业执照上的名称,纳税人税号,如果是开普通增值税发票的 ...

  3. Idea 快捷生成类注释与方法注释

    这篇博客应该在刚使用IDEA 的时候就写了.  但是一直忘了.  今天使用新的api 接口文档生成工具 JApiDocs  的时候,看其上面有编码规范, 注释规范. 就想起了IDEA 类中, 方法中快 ...

  4. xutils工具上传日志文件--使用https并且带进度条显示

    package logback.ecmapplication.cetcs.com.myapplication; import android.app.Activity; import android. ...

  5. Spring IoC 默认标签解析

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...

  6. 4. union-find算法

    算法的主题思想: 1.优秀的算法因为能够解决实际问题而变得更为重要: 2.高效算法的代码也可以很简单: 3.理解某个实现的性能特点是一个挑战: 4.在解决同一个问题的多种算法之间进行选择时,科学方法是 ...

  7. Win8.1安装配置64位Oracle Database 11g的详细图文步骤记录

    在开始Oracle数据安装之前建议:1.关闭本机的病毒防火墙.2.断开互联网. 这样可以避免解压缩丢失文件和安装失败. Step1 Oracle官网下载好Windows系统64位的安装包,下载速度慢的 ...

  8. 分享 HT 实用技巧:实现指南针和 3D 魔方导航

    前言 三维场景时常需要一个导航标识,用来确定场景所处的方位. 一般有两种表现形式:指南针.小方盒(方位魔方). 参考一下百度百科中的 maya 界面,可以看到右上角有一个标识方位的小盒子,说的就是它: ...

  9. 音视频前沿:新一代 AV1 视频标准究竟是怎样一种存在?

    AV1是开放媒体联盟Alliance for Open Media (AOM) 开发的第一代视频编码标准,自推出以来获得了产业界巨大关注和支持.腾讯多媒体实验室也加入进来和其他公司团队一同积极推动AV ...

  10. postman不能启动的问题解决

    1.postman启动不了,启动时提示“postman resolving transporter buffer”,不能正常启动 第一步,删除:在chrome-更多工具-扩展程序里面删除了postma ...