• nodejs之EventEmitter实现


    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')
  • 相关阅读:
    python从入门到实践-5章if语句
    HiveQL:文件格式和压缩方法
    HiveQL:调优
    HiveQL:模式设计
    HiveQL:视图
    (转)配置文件.bash_profile和.bashrc的区别
    Hive-学习总结(二)
    Hive-学习总结
    MYSQL-表类型(存储引擎)的选择
    MYSQL-常用函数
  • 原文地址:https://www.cnblogs.com/kdcg/p/13322994.html
Copyright © 2020-2023  润新知