在 nodejs/events.js 的 emitMany 函数中克隆监听器数组的原因是什么?

What is the reason for cloning the listeners array in nodejs/events.js' emitMany function?

函数代码(source code on github):

function emitMany(handler, isFn, self, args) {
  if (isFn)
    handler.apply(self, args);
  else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i)
      listeners[i].apply(self, args);
  }
}

这一行:

var listeners = arrayClone(handler, len);

克隆了在此范围内命名为 handler 的侦听器数组,然后将其克隆分配给名为 listeners 的新变量。我想知道这有什么用。

我怀疑这是因为侦听器可以从列表中删除自己,并且该操作会破坏 for 循环中的计数器(列表项的索引在删除后会更改,但计数器 i 会盲目地继续不知道这一点)。

我的解释是否正确,或者可能有什么问题else/more?

此行为一般适用于 emit()(而不仅仅是内部 emitAny())并且至少可以防止事件处理程序将自己添加为同一事件(或类似情况),这可能会导致单个 emit() 的无限循环。例如:

emitter.on('foo', function fooHandler() {
  emitter.on('foo', fooHandler);
});

那是因为当发出相应的事件时,处理程序可能会为该事件添加/删除处理程序,从而修改迭代的数组。

foo.on('bar', function() {
  foo.on('bar', function() { // should not be invoked now / but for the next and subsequent events
  })
})

第一次触发 'bar' 事件时不应调用第二个处理程序,因此必须在执行处理程序之前克隆处理程序数组。