删除当前发出的事件的事件侦听器

时间:2014-10-29 15:52:19

标签: node.js events stream

我有以下示例应用程序,用Node.js编写:

'use strict';

var events = require('events'),
    util = require('util');

var EventEmitter = events.EventEmitter;

var Foo = function () {};

util.inherits(Foo, EventEmitter);

var foo = new Foo();

foo.once('x', function () {
  foo.removeAllListeners();
  console.log('Google!');
});

foo.once('x', function () {
  foo.removeAllListeners();
  console.log('Yahoo!');
});

foo.emit('x');

打印:

Google!
Yahoo!

现在我的问题是:显然removeAllListeners不会影响当前绑定到事件的事件侦听器。这是随机的,还是意图? (我用0.10.32以及0.11.13检查了这个)

我的问题的背景是:如果我将两个事件处理程序绑定到流的end事件,其中一个调用removeAllListeners,Node.js是否保证两者都将始终跑步,还是只是祝你好运?

1 个答案:

答案 0 :(得分:2)

在查看.emit()方法的实现时,看起来一旦它开始处理事件并调用侦听器,该事件就不会受到调用removeAllListeners()的任何代码的影响,所以在您的示例中两个听众都会被召唤。

.emit()的代码在执行任何侦听器之前复制了侦听器数组,这样一旦它开始执行一个侦听器,它就会执行所有侦听器,即使它们在执行期间被删除。这是相关的代码:

  } else if (util.isObject(handler)) {
    len = arguments.length;
    args = new Array(len - 1);
    for (i = 1; i < len; i++)
      args[i - 1] = arguments[i];

    listeners = handler.slice();
    len = listeners.length;
    for (i = 0; i < len; i++)
      listeners[i].apply(this, args);
  }

从这里的EventEmitter实现:https://github.com/joyent/node/blob/857975d5e7e0d7bf38577db0478d9e5ede79922e/lib/events.js#L120

在这段代码中,handler将是一个监听器函数数组。这条线

listeners = handler.slice()

在执行任何侦听器之前复制侦听器数组。这是可以预料到的,因为如果代码可以自由地允许修改正在迭代的迭代数组,那么该数组的迭代可能会混乱(重复或跳过)。因此,它会在调用任何侦听器之前冻结要调用的侦听器集。