EventEmitter简介

EventEmitter是Node.js的内置模块events提供的一个类,它是Node事件流的核心,EventEmitter是服务端的东西,
前端已经有event-emitter的npm库
 
高级浏览器也有原生提供的EventTarget这种实现事件监听和触发的API
 
但是它们和Node.js的事件API都有或多或少的区别,今天我们就来实现一个前端版本的EventEmitter
我本章demo的github地址如下
 

API介绍

我们要实现的API有:
  • on(event, listener):为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
  • emit(event, [arg1], [arg2]): 按监听器的顺序执行执行每个监听器
  • addListener(event, listener):on的同名函数(alias)
  • once(event, listener): 和on类似,但只触发一次,随后便解除事件监听
  • removeListener(event, listener): 移除指定事件的某个监听回调
  • removeAllListeners([event]):移除指定事件的所有监听回调
  • setMaxListeners(n):用于提高监听器的默认限制的数量。(默认10监听回调个产生警告)
  • listeners(event): 返回指定事件的监听器数组。
为了保证兼容性和简单性,下面的编码全部基于ES5语法实现
 

构造函数

首先我们需要写一个EventEmitter构造函数,给它设置两个属性listeners和maxListener
function EventEmitter() {
this.listeners = {};
this.maxListener = 10;
}

listeners用于存放事件监听器函数,结构如下:

{
"event1": [f1,f2,f3],
"event2": [f4,f5],
...
}

而maxListener 是设置的某个事件能够添加的监听器的最大数量,超过这个值,需要在控制台输出警告,但不会报错阻止。按照Node的设计,这个值能够通过setMaxListeners动态调整

on方法

  1. 判断该事件的监听器数量是否已超限,超限则报警告
  2. 判断该事件监听器数组是否初始化,若未初始化,则将listeners[event]初始化为数组,并加入监听器cb
  3. 若监听器数组已经被初始化,则判断数组中是否已存在cb,不存在则添加,已存在则不做操作。
  4. 指定addListener等于on方法
EventEmitter.prototype.on = function (event, cb) {
var listeners = this.listeners;
if (listeners[event] && listeners[event].length >= this.maxListener) {
throw console.error('监听器的最大数量是%d,您已超出限制', this.maxListener)
}
if (listeners[event] instanceof Array) {
if (listeners[event].indexOf(cb) === -1) {
listeners[event].push(cb);
}
} else {
listeners[event] = [].concat(cb);
}
} EventEmitter.prototype.addListener = EventEmitter.prototype.on;

emit方法

  1. 通过Array.prototype.slice.call(arguments)取出方法的参数列表args,(因为考虑简单性和兼容性所以采用ES5的冗长编码方式)
  2. 调用args.shift踢掉数组第一个参数即event,留下来的这些是要传给监听器的
  3. 遍历监听器,通过apply方法把上面得到的args参数传进去
EventEmitter.prototype.emit = function (event) {
var args = Array.prototype.slice.call(arguments);
args.shift();
this.listeners[event].forEach(cb => {
cb.apply(null, args);
});
}

removeListener方法

  1. 通过indexOf确定监听器回调在数组listeners[event]中的位置
  2. 通过splice(i,1)删除之
EventEmitter.prototype.removeListener = function (event, listener) {
var listeners = this.listeners;
var arr = listeners[event] || [];
var i = arr.indexOf(listener);
if (i >= 0) {
listeners[event].splice(i, 1);
}
}

once方法

once方法是on方法和removeListener方法的结合:用on方法监听,在回调结束的最后位置,通过removeListener删掉监听函数自身
EventEmitter.prototype.once = function (event, listener) {
var self = this;
function fn() {
var args = Array.prototype.slice.call(arguments);
listener.apply(null, args);
self.removeListener(event, fn);
}
this.on(event, fn)
}

removeAllListener方法

清空listeners[event]数组
EventEmitter.prototype.removeAllListener = function (event) {
this.listeners[event] = [];
}

setMaxListeners方法和listeners方法

EventEmitter.prototype.listeners = function (event) {
return this.listeners[event];
} EventEmitter.prototype.setMaxListeners = function (num) {
this.maxListener = num;
}

Github地址

https://github.com/penghuwan/event-emitter

EventEmitter的前端实现的更多相关文章

  1. 执行 $Gulp 时发生了什么 —— 基于 Gulp 的前端集成解决方案(二)

    前言 文章 在windows下安装gulp —— 基于 Gulp 的前端集成解决方案(一) 中,已经完成对 gulp 的安装,由于是window环境,文中特意提到了可以通过安装 gitbash 来代替 ...

  2. Node.js 教程 05 - EventEmitter(事件监听/发射器 )

    目录: 前言 Node.js事件驱动介绍 Node.js事件 注册并发射自定义Node.js事件 EventEmitter介绍 EventEmitter常用的API error事件 继承EventEm ...

  3. 闲聊——浅谈前端js模块化演变

    function时代 前端这几年发展太快了,我学习的速度都跟不上演变的速度了(门派太多了,后台都是大牛公司支撑类似于facebook的react.google的angular,angular的1.0还 ...

  4. Gulp vs Grunt 前端构建工具对比

    Gulp vs Grunt 前端工程的构建工具对比 1. Grunt -> Gulp 早些年提到构建工具,难免会让人联想到历史比较悠久的Make,Ant,以及后来为了更方便的构建结构类似的Jav ...

  5. 前端工程的构建工具对比 Gulp vs Grunt

    1. Grunt -> Gulp 早些年提到构建工具,难免会让人联想到历史比较悠久的Make,Ant,以及后来为了更方便的构建结构类似的Java项目而出现的Maven.Node催生了一批自动化工 ...

  6. 【前端】Angular2 Ionic2 学习记录

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/angular2_ionic2.html 一.建立项目 ionic start ProductName super ...

  7. BAT 前端开发面试 —— 吐血总结

    更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了腾讯和阿里的内推及百度的实习生招聘,在此总结一下 一是备忘.总结提升,二是希望给大家一些参考 其他面试及基础相关可以参考其他博文: ...

  8. 如何才能成为一个合格的web前端工程师

    转载原文地址:https://juejin.im/post/5cc1da82f265da036023b628 开篇前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快 ...

  9. BAT 前端开发面经 —— 吐血总结

    更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘,在此总结一下 一是备忘.总结提升,二是希望给大家一些参考 其他面试及基础相关可以参考其他博文: ...

随机推荐

  1. java学习笔记(基础篇)—java数组

    一:什么是数组,什么时候使用数组? 数组是用来保存一组数据类型相同的元素的有序集合,数组中的每个数据称为元素.有序集合可以按照顺序或者下标取数组中的元素. 在Java中,数组也是Java对象.数组中的 ...

  2. cozmo 入坑日记及开发环境搭建

    前几日,朋友在群里发了一个机器人的小视频,视频里机器人可以对话,可以推箱子,开心以后会哈哈大笑,非常有趣. 详细了解里一下,这是个叫 cozmo 的智能机器人,可以配合 SDK 用 python 编程 ...

  3. 1.svn 彻底clear时,注意代码备份 2.借助vc助手加头文件

    1.svn 彻底clear时,注意代码备份 2.不小心彻底clear可以在回收站找到 3.借助vc助手加头文件

  4. 洛谷P1033 自由落体 题解

    题目链接:https://www.luogu.org/problemnew/show/P1033 呵呵,真的学好物理比较重要,前些年卡在这题上的我今天终于会做了,可恶的自由落体(也许是我太弱了吧 ) ...

  5. python迭代器-迭代器取值-for循环-生成器-yield-生成器表达式-常用内置方法-面向过程编程-05

    迭代器 迭代器 迭代: # 更新换代(其实也是重复)的过程,每一次的迭代都必须基于上一次的结果(上一次与这一次之间必须是有关系的) 迭代器: # 迭代取值的工具 为什么用迭代器: # 迭代器提供了一种 ...

  6. HTML介绍和标签

    1.HTML介绍 1.概述 html不是一种编程语言,是一种描述性的标记语言,用于描述超文本内容的显示方式.比如字体,颜色,大小等. 超文本:音频,视频,图片称为超文本. 标记:<英文单词或者字 ...

  7. 第2个C# Winform实例,寻找三角形的位置

    这里,在第一个例子的基础上,稍微做修改,达到最终定位三角形位置的目的. 先在网络上找一张包含有三角形的图片,我们这里使用一张有三个三角形和一些标记的图片来处理. 原图: 先贴结果图片:左侧,中间,右侧 ...

  8. C语言编程入门之--第二章编译环境搭建

    第二章 编译环境搭建 导读:C语言程序如何工作,首先需要编译链接成可执行文件,然后就可以运行在不同的环境中,这个“环境”的意思就是比如说,电脑,手机,路由器,蓝牙音箱等等智能设备中,其中编译器启到了关 ...

  9. tornado并发性能测试

    1.带server2.0装饰器 接口访问数据库查询 并发100 平均每秒处理11.8次请求 平均响应时间6944ms 接口不做任何处理 并发100 平均每秒处理99.9次请求 平均响应时间3ms 并发 ...

  10. 【Python-django后端开发】logging日制配置详解!!!

    官方文档请查看:https://docs.djangoproject.com/en/1.11/topics/logging/ 1. 配置工程日志,在setting.py里,如下 LOGGING = { ...