Node 核心模块 event 源码

简单实现

class EventEmitter {
  constructor() {
    this._event = {}
  }
  on(name, handler) {
    this._event[name] = handler
  }
  emit(name) {
    this._event[name]()
  }
}

来解析这段源码

const EventEmitter = require('events');
const myEmitter = new EventEmitter();

myEmitter.on('qweasd', function (a, b) {
  console.log(a, b, this === myEmitter);
});

// a b true
myEmitter.emit('qweasd', 'a', 'b');

拆开来看

初始化

const EventEmitter = require('events');
const myEmitter = new EventEmitter();
console.log(myEmitter)

EventEmitter {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
[Symbol(kCapture)]: false
}

对应源码

function EventEmitter(opts) {
  EventEmitter.init.call(this, opts);
}

EventEmitter.init = function(opts) {

  if (this._events === undefined ||
      this._events === ObjectGetPrototypeOf(this)._events) {
    // 创建一个空的对象
    this._events = ObjectCreate(null);
    this._eventsCount = 0;
  }

  this._maxListeners = this._maxListeners || undefined;


  if (opts?.captureRejections) {
    validateBoolean(opts.captureRejections, 'options.captureRejections');
    this[kCapture] = Boolean(opts.captureRejections);
  } else {
    // Assigning the kCapture property directly saves an expensive
    // prototype lookup in a very sensitive hot path.
    this[kCapture] = EventEmitter.prototype[kCapture];
  }
};

module.exports = EventEmitter;
EventEmitter.EventEmitter = EventEmitter;

new EventEmitter() 中 最重要的就是创建了一个 _event 的空对象

module.exports = EventEmitter;
EventEmitter.EventEmitter = EventEmitter;

这两句使得如下两种引用都是可行的

const EventEmitterME = require('events');
const { EventEmitter } = require('events')

const myEmitter = new EventEmitter();
const myEmitterME = new EventEmitterME();
console.log(myEmitter)
console.log(myEmitterME)

注册事件

const EventEmitter = require('events');
const myEmitter = new EventEmitter();

myEmitter.on('qweasd', function (a, b) {
  console.log(a, b, this === myEmitter);
});
console.log(myEmitter)

EventEmitter {
_events: [Object: null prototype] { qweasd: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
[Symbol(kCapture)]: false
}

可以看到, 就是给 _events 这个对象上添加一个属性

如果你给同个 EventEmitter 实例添加相同名字的事件, _event 上添加的属性的属性值是个数组

const EventEmitter = require('events');
const myEmitter = new EventEmitter();

myEmitter.on('qweasd', function (a, b) {
  console.log('aaa')
});
myEmitter.on('qweasd', function (a, b) {
  console.log('bbb')
});
console.log(myEmitter)

EventEmitter {
_events: [Object: null prototype] {
qweasd: [ [Function (anonymous)], [Function (anonymous)] ]
},
_eventsCount: 1,
_maxListeners: undefined,
[Symbol(kCapture)]: false
}


当注册一个新事件之前, 如果注册了 newListener 事件, 首先会触发 newListener 事件

const EventEmitter = require('events');

const myEmitter = new EventEmitter();
// Only do this once so we don't loop forever
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // Insert a new listener in front
    myEmitter.on('event', () => {
      console.log('B');
    });
  }
});
myEmitter.on('event', () => {
  console.log('A');
});
myEmitter.emit('event');

B
A

on 就是调用 addListener 函数
源码如下, 核心代码就是 if (existing === undefined) 下的 events[type] = listener; (event 就是 _events) 将 listener 添加到 _event 这个对象上

EventEmitter.prototype.on = EventEmitter.prototype.addListener;

EventEmitter.prototype.addListener = function addListener(type, listener) {
  return _addListener(this, type, listener, false);
};

function _addListener(target, type, listener, prepend) {
  let m;
  let events;
  let existing;

  checkListener(listener);

  events = target._events;
  if (events === undefined) {
    events = target._events = ObjectCreate(null);
    target._eventsCount = 0;
  } else {
    // To avoid recursion in the case that type === "newListener"! Before
    // adding it to the listeners, first emit "newListener".
    if (events.newListener !== undefined) {
      target.emit('newListener', type,
                  listener.listener ?? listener);

      // Re-assign `events` because a newListener handler could have caused the
      // this._events to be assigned to a new object
      events = target._events;
    }
    existing = events[type];
  }

  if (existing === undefined) {
    // Optimize the case of one listener. Don't need the extra array object.
    // 给对应的 events, 即 target._events 添加注册的 listener
    events[type] = listener;
    ++target._eventsCount;
  } else {
    if (typeof existing === 'function') {
      // Adding the second element, need to change to array.
      existing = events[type] =
        prepend ? [listener, existing] : [existing, listener];
      // If we've already got an array, just append.
    } else if (prepend) {
      existing.unshift(listener);
    } else {
      existing.push(listener);
    }

    // Check for listener leak
    m = _getMaxListeners(target);
    if (m > 0 && existing.length > m && !existing.warned) {
      existing.warned = true;
      // No error code for this since it is a Warning
      // eslint-disable-next-line no-restricted-syntax
      const w = new Error('Possible EventEmitter memory leak detected. ' +
                          `${existing.length} ${String(type)} listeners ` +
                          `added to ${inspect(target, { depth: -1 })}. Use ` +
                          'emitter.setMaxListeners() to increase limit');
      w.name = 'MaxListenersExceededWarning';
      w.emitter = target;
      w.type = type;
      w.count = existing.length;
      process.emitWarning(w);
    }
  }

  return target;
}

触发事件

可以看到, emit 就是触发 _event 对象上对应某个 type 的特定的函数

EventEmitter.prototype.emit = function emit(type, ...args) {
  let doError = (type === 'error');

  const events = this._events;
  if (events !== undefined) {
    if (doError && events[kErrorMonitor] !== undefined)
      this.emit(kErrorMonitor, ...args);
    doError = (doError && events.error === undefined);
  } else if (!doError)
    return false;

  // If there is no 'error' event listener then throw.
  if (doError) {
    let er;
    if (args.length > 0)
      er = args[0];
    if (er instanceof Error) {
      try {
        const capture = {};
        ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
        ObjectDefineProperty(er, kEnhanceStackBeforeInspector, {
          value: FunctionPrototypeBind(enhanceStackTrace, this, er, capture),
          configurable: true
        });
      } catch {}

      // Note: The comments on the `throw` lines are intentional, they show
      // up in Node's output if this results in an unhandled exception.
      throw er; // Unhandled 'error' event
    }

    let stringifiedEr;
    try {
      stringifiedEr = inspect(er);
    } catch {
      stringifiedEr = er;
    }

    // At least give some kind of context to the user
    const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
    err.context = er;
    throw err; // Unhandled 'error' event
  }

  const handler = events[type];

  if (handler === undefined)
    return false;

  if (typeof handler === 'function') {
    // 触发 _event 对象上对应某个 type 的特定的函数
    const result = handler.apply(this, args);

    // We check if result is undefined first because that
    // is the most common case so we do not pay any perf
    // penalty
    if (result !== undefined && result !== null) {
      addCatch(this, result, type, args);
    }
  } else {
    const len = handler.length;
    const listeners = arrayClone(handler);
    for (let i = 0; i < len; ++i) {
      const result = listeners[i].apply(this, args);

      // We check if result is undefined first because that
      // is the most common case so we do not pay any perf
      // penalty.
      // This code is duplicated because extracting it away
      // would make it non-inlineable.
      if (result !== undefined && result !== null) {
        addCatch(this, result, type, args);
      }
    }
  }

  return true;
};

参考
官方文档
Nodejs源码解析之events

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值