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. git 本机链接多库配置

    git config --list 查看所有配置 // 提交时读取用户名称及邮箱优先级 --local > --global > --system // 全局配置用户名称及邮箱 git c ...

  2. 万级TPS亿级流水-中台账户系统架构设计

    万级TPS亿级流水-中台账户系统架构设计 标签:高并发 万级TPS 亿级流水 账户系统 背景 业务模型 应用层设计 数据层设计 日切对账 背景 我们需要给所有前台业务提供统一的账户系统,用来支撑所有前 ...

  3. 2.WebPack初始化

    一.Package.json 在项目中输入: npm init 之后会提示你一步一步输入信息,我输入的信息如下: 生成的Package.json文件如下 我们也可以在初始时省略这些步骤,让脚本使用默认 ...

  4. .Net Core Configuration源码探究

    前言     上篇文章我们演示了为Configuration添加Etcd数据源,并且了解到为Configuration扩展自定义数据源还是非常简单的,核心就是把数据源的数据按照一定的规则读取到指定的字 ...

  5. PHPWord中文乱码、单元格合并、动态表格模板解决方案合集

    摘要:  最近一个项目开发要用到PHP技术导出Word文档,采用PHPWord插件,版本为0.6.2 beta,CodePlex已停止维护.网上还有另外一个版本的PhpWord,项目类名大小写上略有不 ...

  6. JavaWeb网上图书商城完整项目--day02-11.激活功能流程分析

    1.当用户注册成功之后,会给用户发送邮件,当用户点击邮件的激活按钮的时候,会调用UserServlet中的activation的方法,并且会把激活码传递到后台,后台业务层对业务进行操作

  7. nmap二层发现

    使用nmap进行arp扫描要使用一个参数:-sn,该参数表明屏蔽端口扫描而只进行arp扫描. nmap支持ip段扫描,命令:nmap -sn 192.168.1.0/24 nmap速度比arping快 ...

  8. 在Ubuntu上实现人脸识别登录

    安装Howdy: howdy项目地址 sudo add-apt-repository ppa:boltgolt/howdy sudo apt update sudo apt install howdy ...

  9. maven在windows10系统下安装配置和打包war

    maven下载地址:http://maven.apache.org/ 下载完成解压到 D盘 目录下D:\apache-maven-3.5.0\bin 配置maven环境变量: M2_HOME   D: ...

  10. 《UNIX环境高级编程》(APUE) 笔记第三章 - 文件I/O

    3 - 文件I/O Github 地址 1. 文件描述符 对于内核而言,所有打开的文件都通过 文件描述符 (file descriptor) 引用.当打开一个现有文件或创建一个新文件时,内核向进程返回 ...