marzelin
marzelin

Reputation: 11610

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

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?

Upvotes: 0

Views: 195

Answers (2)

lipp
lipp

Reputation: 5936

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.

Upvotes: 1

mscdex
mscdex

Reputation: 106746

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);
});

Upvotes: 1

Related Questions