资讯专栏INFORMATION COLUMN

EventEmitter

sixleaves / 2016人阅读

摘要:工具函数判断所属类型判断是否是或者添加事件监听事件的名称监听事件对应的方法改变的指向执行的主体是否只执行一次必须是一个函数如果只执行一次将是一次函数如果已经存在监听一个函数则将是一个数组如果存在监听多个函数数组则类初始化属性添加事件可执行

//工具函数,判断所属类型,判断是否是null或者undefined
const toString = Object.prototype.toString;
const isType = obj => toString.call(obj).slice(8, -1).toLowerCase();
const isArray = obj => Array.isArray(obj) || isType(obj) === "array";
const isNullOrUndefined = obj => obj === null || obj === undefined;
/**
 * 添加事件
 * @param {*} type 监听事件的名称
 * @param {*} fn   监听事件对应的方法
 * @param {*} context 改变this的指向/执行的主体
 * @param {*} once 是否只执行一次
 */
const _addListener = function(type, fn, context, once) {
  if (typeof fn != "function") {
    throw new TypeError("fn 必须是一个函数");
  }
  fn.context = context;
  fn.once = !!once;
  const event = this._events[type];
  //如果只执行一次, this._events[type] 将是一次函数
  if (isNullOrUndefined(event)) {
    this._events[type] = fn;
  } else if (typeof event === "function") {
    //如果已经存在(监听)一个函数,则this._events[type]将是一个数组
    this._events[type] = [event, fn];
  } else if (isArray(event)) {
    //如果存在(监听)多个函数(数组),则push
    this._events[type].push(fn);
  }
  return this;
}

//EventEmitter类
class EventEmitter {
  constructor() {
    //初始化_events属性
    if (isNullOrUndefined(this._events)) {    
      this._events = Object.create(null);
    }
  }
  //添加事件
  addListener(type, fn, context) {
    return _addListener.call(this, type, fn, context);
  }
  //可执行多次
  on(type, fn, context) {
    return this.addListener(type, fn, context);
  }
  //执行一次
  once(type, fn, context) {
    return _addListener.call(this, type, fn, context, true);
  }
  //事件触发
  emit(type, ...rest) {
    if (isNullOrUndefined(type)) {
      throw new Error("emit必须接收至少一个参数");
    }
    const events = this._events[type];
    if (isNullOrUndefined(events)) return false;
    if (typeof events === "function") {
      //用call改变this的指向指向events.context主体,否则指向null
      events.call(events.context || null, rest);
      //执行完毕判断是否只执行一次,是则移除
      if (events.once) {
        this.removeListener(type, events);
      }
    } else if (isArray(events)) {
      events.map(e => {
        e.call(e.context || null, rest);
        if (e.once) {
          this.removeListener(type, e);
        }
      })
    }
    return true;
  }
  //事件移除
  removeListener(type, fn) {
    if (isNullOrUndefined(this._events)) return this;
    if (isNullOrUndefined(type)) return this;
    if (typeof fn !== "function") {
      throw new Error("fn 必须是一个函数");
    }
    const events = this._events[type];
    if (typeof events === "function") {
      events === fn && delete this._events[type];
    } else {
      const findIndex = events.findIndex(e => e === fn);
      if (findIndex === -1) return this;
      if (findIndex === 0) {
        events.shift();
      } else {
        events.splice(findIndex, 1);
      }
      //如果只剩下一个监听者,则把数组变为函数
      if (events.length === 1) {
        this._events[type] = events[0];
      }
    }
    return this;
  }
  //删除所有事件
  removeAllListeners(type) {
    if (isNullOrUndefined(this._events)) return this;
    //如果没有指定type,则删除全部
    if (isNullOrUndefined(type)) this._events = Object.create(null);
    const events = this._events[type];
    if (!isNullOrUndefined(events)) {
      //判断是否只剩下最后一个事件
      if (Object.keys(this._events).length === 1) {
        this._events = Object.create(null);
      } else {
        delete this._events[type];
      }
    }
    return this;
  }
  //监听队列
  listeners(type) {
    if (isNullOrUndefined(this._events)) return [];
    const events = this._events[type];
    return isNullOrUndefined(events) ? [] : (typeof events === "function" ? [events] : events.map(o => o));
  }
  //监听者数量
  listenerCount(type) {
    if (isNullOrUndefined(this._events)) return 0;
    const events = this._events[type];
    return isNullOrUndefined(events) ? 0 : (typeof events === "function" ? 1 : events.length);
  }
  eventNames() {
    if (isNullOrUndefined(this._events)) return [];
    return Object.keys(this._events);
  }
}

参考自https://www.php.cn/js-tutoria... 作者:php中世界最好的语言

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106735.html

相关文章

  • 循序渐进教你实现一个完整的node的EventEmitter模块

    摘要:本文从的的使用出发,循序渐进的实现一个完整的模块。移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器的别名移除所有事件的所有监听器,如果指定事件,则移除指定事件的所有监听器。返回指定事件的监听器数组。 node的事件模块只包含了一个类:EventEmitter。这个类在node的内置模块和第三方模块中大量使用。EventEmitter本质上是一个观察者模式的实现,这种模式可...

    sunsmell 评论0 收藏0
  • 【Node事件模块Events】

    环境:Node v8.2.1; Npm v5.3.0;OS Windows10 1、 Node事件介绍 Node大多数核心 API 都采用惯用的异步事件驱动架构,其中某些类型的对象(触发器)会周期性地触发命名事件来调用函数对象(监听器)。 所有能触发事件的对象都是 EventEmitter 类的实例。 这些对象开放了一个 eventEmitter.on() 函数,允许将一个或多个函数绑定到会被对象...

    junnplus 评论0 收藏0
  • 【node不完全指西】EventEmitter (事件发布/订阅模式)解析

    摘要:从异步编程解决方案说起吧事件发布订阅模式模式流程控制库事件发布订阅模式事件监听器模式是一种广泛运用于异步编程的模式,是回调函数的事件话,又称发布订阅模式。 从node异步编程解决方案说起吧: 事件发布/订阅模式 Promise/deferred模式 流程控制库 事件发布/订阅模式 事件监听器模式是一种广泛运用于异步编程的模式,是回调函数的事件话,又称发布/订阅模式。 主要实现的几个...

    yagami 评论0 收藏0
  • NodeJS Events 必知必会

    摘要:超过会有警告输出。实例默认的某个事件最大监听者的数量,默认是。事件监听数量是检测内存泄露的一个标准一个维度。例如同一个实例类型事件个监听者,类型事件个监听者,这个并不会有告警。 1. 环境 node 8.11.3 2. 基本使用 // 01.js const EventEmitter = require(events); class MyEmitter extends EventE...

    bladefury 评论0 收藏0
  • 【每日一包0025】events

    摘要:打印的参数分别为移除的监听事件和该事件的句柄函数默认情况下,每个事件可以注册最多个监听器。返回已注册监听器的事件名数组。值设为或表示不限制监听器的数量。持续地记录返回一个数组,只包含绑定的监听器。 [github地址:https://github.com/ABCDdouyae...] events 事件触发器 大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些...

    shixinzhang 评论0 收藏0
  • 【每日一包0025】events

    摘要:打印的参数分别为移除的监听事件和该事件的句柄函数默认情况下,每个事件可以注册最多个监听器。返回已注册监听器的事件名数组。值设为或表示不限制监听器的数量。持续地记录返回一个数组,只包含绑定的监听器。 [github地址:https://github.com/ABCDdouyae...] events 事件触发器 大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些...

    fxp 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<