Skip to content

EventEmitter

什么是 EventEmitter

EventEmitter 是 Node.js 中一个非常重要的模块,许多模块都继承了它。EventEmitter 的核心就是事件触发与事件监听器功能的封装。

发射器对象(EventEmitter)发出事件,这些事件会导致调用之前注册的监听器,因此,发射器对象具有两个基本功能:

  • 发射事件
  • 注册/注销监听器

事件注册方法

addListener(event, listener)

js
addListener(event, fn) {
    this.listeners[event] = this.listeners[event] || [];
    this.listeners[event].push(fn);
    return this;
}

addListener 方法会检查事件是否已注册,如果是,则返回已注册的数组,否则返回一个新数组。然后将“fn”添加到数组中。

TIP

可以针对同一事件注册多个回调。

on(event, listener)

js
on(event, fn) {
    return this.addListener(event, fn);
}

on 方法只是 addListener 方法的别名。

事件注销方法

removeListener(event, listener)

js
removeListener (event, fn) {
    let lis = this.listeners[event];
    if (!lis) return this;
    for(let i = lis.length; i > 0; i--) {
      if (lis[i] === fn) {
        lis.splice(i,1);
        break;
      }
    }
    return this;
}

removeListener 方法会按事件获取监听器数组,然后遍历监听器数组,找到与“fn”相同的监听器,然后删除。

TIP

如果同一事件注册了多个回调,只会删除一个,其他回调不受影响。

off(event, listener)

js
off(event, fn) {
    return this.removeListener(event, fn);
}

off 方法只是 removeListener 方法的别名。

事件触发方法

once(event, listener)

js
once(eventName, fn) {
    this.listeners[event] = this.listeners[eventName] || [];
    const onceWrapper = () => {
      fn();
      this.off(eventName, onceWrapper);
    }
    this.listeners[eventName].push(onceWrapper);
    return this;
}

once 方法会注册一个只执行一次的监听器,当事件被触发时,监听器会被移除。

once 方法中创建了一个名为 onceWrapper 的包装函数,它会在触发事件时执行 fn 并移除监听器。

emit(event, ...args)

js
emit(eventName, ...args) {
    let fns = this.listeners[eventName];
    if (!fns) return false;
    fns.forEach((f) => {
      f(...args);
    });
    return true;
}

emit 方法会按事件注册顺序同步调用监听器数组中的每个监听器,并将提供的参数传递给每个监听器。

事件查询方法

listenerCount(event)

js
listenerCount(eventName) {
    let fns = this.listeners[eventName] || [];
    return fns.length;
}

listenerCount 方法返回指定事件的监听器数量。

rawListeners(event)

js
rawListeners(event) {
    return this.listeners[event];
}

rawListeners 返回指定事件的监听器数组副本,如果事件已经发出一次,返回的数组中的监听器不包括 once 注册的监听器。

完整代码实现

js
class EventEmitter {
  listeners = {}
  
  addListener(eventName, fn) {
    this.listeners[eventName] = this.listeners[eventName] || [];
    this.listeners[eventName].push(fn);
    return this;
  }

  on(eventName, fn) {
    return this.addListener(eventName, fn);
  }

  once(eventName, fn) {
    this.listeners[eventName] = this.listeners[eventName] || [];
    const onceWrapper = () => {
      fn();
      this.off(eventName, onceWrapper);
    }
    this.listeners[eventName].push(onceWrapper);
    return this;
  }

  off(eventName, fn) {
    return this.removeListener(eventName, fn);
  }

  removeListener (eventName, fn) {
    let lis = this.listeners[eventName];
    if (!lis) return this;
    for(let i = lis.length; i > 0; i--) {
      if (lis[i] === fn) {
        lis.splice(i,1);
        break;
      }
    }
    return this;
  }

  emit(eventName, ...args) {
    let fns = this.listeners[eventName];
    if (!fns) return false;
    fns.forEach((f) => {
      f(...args);
    });
    return true;
  }

  listenerCount(eventName) {
    let fns = this.listeners[eventName] || [];
    return fns.length;
  }

  rawListeners(eventName) {
    return this.listeners[eventName];
  }
}

API 文档参考