我有以下用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是否保证两者都将始终运行,或者这只是运气好吗?
在查看.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()
在执行任何侦听器之前,制作侦听器数组的副本。这是意料之中的事,因为如果在迭代时允许代码自由修改正在迭代的数组,那么该数组的迭代可能会被打乱(重复或跳过)。因此,它会在调用任何一个侦听器之前冻结要调用的侦听器集。