The Future Depends on You
首页/nodejs/events - (事件触发器) 核心方法实现/
events - (事件触发器) 核心方法实现
上次更新时间:2021-2-03 文章分类:nodejs 阅读人数:34

1. events 简介

大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。

所有能触发事件的对象都是 EventEmitter 类的实例。 这些对象有一个 eventEmitter.on() 函数,用于将一个或多个函数绑定到命名事件上。

当 EventEmitter 对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用。 被调用的监听器返回的任何值都将会被忽略并丢弃。

-- 节选自 events(事件触发器)

2. events.on

添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 与 listener 会导致 listener 会被添加多次。

code:

function EventEmitter() {
  this._event = {}
}

/**
 * 订阅
 * @param {*} eventName
 * @param {*} callback
 */
EventEmitter.prototype.on = function (eventName, callback) {
  if (!this._event) {
    this._event = Object.create(null)
  }
  if (this._event[eventName]) {
    this._event[eventName].push(callback)
  } else {
    this._event[eventName] = [callback]
  }
}

3. events.emit

按照监听器注册的顺序,同步地调用每个注册到名为 eventName 的事件的监听器,并传入提供的参数。

code:

/**
 * 发布
 * @param {*} eventName
 * @param  {...any} args
 */
EventEmitter.prototype.emit = function (eventName, ...args) {
  if (!this._event) return
  if (this._event[eventName]) {
    this._event[eventName].forEach((fn) => fn(...args))
  }
}

4. events.once

添加单次监听器 listener 到名为 eventName 的事件。 当 eventName 事件下次触发时,监听器会先被移除,然后再调用。

code:

/**
 * 绑定一次
 * @param {*} eventName
 * @param {*} callback
 */
EventEmitter.prototype.once = function (eventName, callback) {
  const once = (...args) => {
    callback(...args)
    // 第一次触发后将自身删除
    this.off(eventName, once)
  }
  // 标识这个once是谁的
  once.l = callback
  this.on(eventName, once)
}

5. events.off

从名为 eventName 的事件的监听器数组中移除指定的 listener。

code:

/**
 * 删除
 * @param {*} eventName
 * @param {*} callback
 */
EventEmitter.prototype.off = function (eventName, callback) {
  if (!this._event) return
  if (this._event[eventName]) {
    this._event[eventName] = this._event[eventName].filter((fn) => fn !== callback && fn.l !== callback)
  }
}

6. newListener

EventEmitter 实例在新的监听器被添加到其内部监听器数组之前,会触发自身的 'newListener' 事件。

为 'newListener' 事件注册的监听器将传递事件名称和对要添加的监听器的引用。

在添加监听器之前触发事件的事实具有微妙但重要的副作用:在 'newListener' 回调中注册到相同 name 的任何其他监听器将插入到正在添加的监听器之前。

code:

EventEmitter.prototype.on = function (eventName, callback) {
  if (!this._event) {
    this._event = Object.create(null)
  }
+ // 当前绑定的不是newListener事件就触发
+ if (eventName !== 'newListener') {
+   this.emit('newListener', eventName)
+ }
  if (this._event[eventName]) {
    this._event[eventName].push(callback)
  } else {
    this._event[eventName] = [callback]
  }
}

7. 测试

code:

const EventEmitter = require('./events')

// node 提供的工具模块
const util = require('util')

function Test() {}

// Test 继承 EventEmitter
util.inherits(Test, EventEmitter)

let test = new Test()

function test_one() {
  console.log('test_one')
}
function test_two() {
  console.log('test_two')
}
function test_three() {
  console.log('test_three')
}

test.once('newListener', (type) => {
  console.log(type)
})

test.on('_test_', test_one)
test.on('_test_', test_two)
test.on('_test_', test_three)

test.off('_test_', test_two)

test.emit('_test_')

执行结果:

------------events-(事件触发器)------------

_test_
test_one
test_three

------------events-(事件触发器)------------
  • 完结.