创建特定的循环行为

Creating particular loop behavior

在为我的项目创建内部 EventEmitter 时,我开始好奇如何为附加的事件处理程序生成特定的循环迭代行为。这是我关注的一个例子:

MyEventEmitter.prototype.emit = function (name, event) {
    var index;

    if (name in this.events) {
        for (index = 0; index < this.events[name].length; index++) {
            this.events[name][index].call(this, event);
        }
    }
};

澄清一下,this.events 是一个对象,每个键都是一个事件名称,每个值都是要为相应事件调用的事件处理程序数组。

然而,正如我在 中观察到的那样,对于附加在 MyEventEmitter.prototype.once 中的事件处理程序,这将失败,因为包装事件处理程序函数将自行删除,导致迭代跳过数组的索引紧跟在数组中的一次性事件处理程序之后。这就是我的意思:

var array = [1, 2, 3, 4, 5], index;

for (index = 0; index < array.length; index++) {
    // log event handlers that get called
    console.log(array[index]);
    // let's assume that `3` is like an event handler that removes itself
    if (array[index] === 3) {
        array.splice(index, 1);
    }
}

这将记录以下内容:

1
2
3
5

请注意,4 不会被迭代,因为 3 会自行删除。我将如何写 emit 来适应这个?或者,如果合适,EventEmitter 的本机实现如何处理这个问题?

自己查看节点源后发现their solution in events.js:

listeners = handler.slice();

基本上,它会制作一个要迭代的侦听器数组的副本,这样如果侦听器从原始数组中删除自己,副本的索引不受影响。