0

The function code (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);
  }
}

In this line:

var listeners = arrayClone(handler, len);

an array of listeners, named in this scope as handler, is cloned, and then its clone is assigned to a new variable named listeners. I wonder what is this useful for.

I suspect it's because a listener can remove itself from the list, and that action would break the counter in the for loop (the list items' indexes would change after the removal, but the counter i would blindly keep going unaware of that).

Is my explanation correct, or maybe there's something else/more to it?

marzelin
  • 10,790
  • 2
  • 30
  • 49

2 Answers2

1

This behavior is for emit() in general (not just the internal emitAny()) and exists to at least prevent situations where an event handler adds itself as an event handler for the same event (or similar situations) which could cause unbounded looping for a single emit(). For example:

emitter.on('foo', function fooHandler() {
  emitter.on('foo', fooHandler);
});
mscdex
  • 104,356
  • 15
  • 192
  • 153
1

that's because when the respective event is emitted, the handler might add / remove handlers for that very event thus modifying the array which is iterated.

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

the second handler should not be called when the 'bar' event is fired the first time, thus the array of handlers must be cloned before executing the handlers.

lipp
  • 5,586
  • 1
  • 21
  • 32