Node.js事件发射器源代码的说明

Ale*_*lls 1 javascript node.js

我正在寻找Node.js事件发射器的源代码

https://github.com/nodejs/node/blob/master/lib/events.js

我试图弄清楚代码如何识别功能,特别是在使用addListener/时removeListener

这些函数都接受(String s,Function f)的签名

但我不了解的是它们如何识别调用removeListener时要删除的函数,因为可能有多个函数充当同一事件的回调。

我想我特别想知道这条线

list[i] === listener
Run Code Online (Sandbox Code Playgroud)

也就是说,比较两个函数是否相等,可以在JS中使用

jfr*_*d00 5

但我不了解的是它们如何识别调用removeListener时要删除的函数,因为可能有多个函数充当同一事件的回调。

一个eventEmitter对象(或从其继承的任何对象)存储着它正在管理其侦听器的所有事件名称的映射。然后,它可以为地图中的每个事件名称存储一个函数数组。 addListener()在右边的列表中添加一个函数,并removeListener()从右边的列表中删除匹配的函数。当您这样做时:

obj.addListener("someEvent", someFunction);
Run Code Online (Sandbox Code Playgroud)

eventEmitter对象确保“ someEvent”在它正在管理的事件名称的映射中,并且正在为该特定事件名称的侦听器数组添加someFunction。给定事件名称可以有多个侦听器,因此,只要有多个侦听器,就eventEmitter使用一个数组,以便它可以存储该特定事件的所有侦听器功能。

两个代码addListener(),并removeListener()通过优化复杂了不少,无论实施,这使得它更难以跟随代码。如果给定事件有多个侦听器,则代码在事件映射中存储一系列侦听器函数。但是,如果只有一个侦听器,那么它只会存储一个侦听器(没有数组)。这意味着任何使用侦听器列表的代码都必须首先检查它是单个侦听器还是侦听器数组。

removeListener()有两个参数,一个事件类型和一个函数。目的是为该事件找到一个先前注册的侦听器,并注册该特定功能。

发射器对象本身为每种事件类型存储一个函数数组。因此,在removeListener(type, listener)被调用时,调用方将传入事件类型和特定函数。eventEmitter代码将在其数据中查找为传入的特定事件类型的侦听器列表,然后在该侦听器列表中搜索与传入的特定侦听器匹配的事件。如果找到,它将被删除。

这是代码的带注释的副本,应解释该removeListener()函数中每个代码块中的情况:

// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener =
    function removeListener(type, listener) {
      var list, events, position, i;

      // make sure that listener was passed in and that it's a function
      if (typeof listener !== 'function')
        throw new TypeError('"listener" argument must be a function');

      // get the map of events we have listeners for
      events = this._events;
      if (!events)
        return this;

      // get the list of functions for the specific event that was passed in
      list = events[type];
      if (!list)
        return this;

      // handle some special cases when there is only one listener for an event
      if (list === listener || (list.listener && list.listener === listener)) {
        if (--this._eventsCount === 0)
          this._events = {};
        else {
          delete events[type];
          if (events.removeListener)
            this.emit('removeListener', type, listener);
        }
      } else if (typeof list !== 'function') {
        // when not a special case, we will have to find the right
        // function in the array so initialize our position variable
        position = -1;

        // search backward through the array of functions to find the
        // matching function
        for (i = list.length; i-- > 0;) {
          if (list[i] === listener ||
              (list[i].listener && list[i].listener === listener)) {
            position = i;
            break;
          }
        }

        // if we didn't find it, nothing to do so just return
        if (position < 0)
          return this;

        // if the list has only one function in it, then just clear the list
        if (list.length === 1) {
          list[0] = undefined;
          if (--this._eventsCount === 0) {
            this._events = {};
            return this;
          } else {
            delete events[type];
          }
        } else {
          // remove that one function from the array
          spliceOne(list, position);
        }

        // send out an event if we actually removed a listener
        if (events.removeListener)
          this.emit('removeListener', type, listener);
      }

      return this;
    };
Run Code Online (Sandbox Code Playgroud)

添加了基于注释的解释:

Javascript中的函数是一流的对象。当代码使用=====比较两个函数或将变量与函数引用进行比较时,Javascript只是进行比较以查看每个操作数是否引用相同的基础Javascript对象。这里没有.toString()被使用。只是进行测试以查看它们是否引用相同的物理对象。

这是几个例子:

function myFunc() {
   console.log("hello");
}

var a = myFunc;
if (a === myFunc) {
    console.log("Yes, a does refer to myFunc");
}

var b = a;
if (b === a) {
    console.log("Yes, a and b refer to the same function");
}

function myFunc2() {
   console.log("hello");
}

a = myFunc;
b = myFunc2;

if (a !== b) {
    console.log("a and b do not refer to the same function");
}
Run Code Online (Sandbox Code Playgroud)

或者,更像是正在工作的片段addListener()及其removeListener()中使用的内容:

obj.addListener("someEvent", someFunction);
Run Code Online (Sandbox Code Playgroud)