0

In a discussion at Passing 'this' and argument to addEventListener function without using bind, caching functions was mentioned.

For example, considering the following Event Listeners:

window.addEventListener('event1', callback1, false);
window.addEventListener('event2', callback2, false);
window.addEventListener('event3', callback3, false);
window.addEventListener('event4', callback4, false);
window.addEventListener('event5', callback5, false);

Can their removal be cached (for example in an array)?

var unloaders = []; // Keeps track of unloader functions
unloaders.push(window.removeEventListener('event1', callback1, false));
unloaders.push(window.removeEventListener('event2', callback2, false));
unloaders.push(window.removeEventListener('event3', callback3, false));
unloaders.push(window.removeEventListener('event4', callback4, false));
unloaders.push(window.removeEventListener('event5', callback5, false));

Finally, if they can be cached, how can they be executed at the correct time?

for (let i = 0, len = unloaders.length; i < len; i++) {
  //
}
Community
  • 1
  • 1
erosman
  • 7,094
  • 7
  • 27
  • 46

1 Answers1

1

unloaders.push(window.removeEventListener('event1', callback1, false)) will not put the function in the array to be executed later, but execute the function and put the result value into the array, i.e. not what you want.

The unload from the other question will actually construct an anonymous closure function and put it into the array, so simplified:

var unloaders = []; // Keeps track of unloader functions
unloaders.push(function() {
  window.removeEventListener('event2', callback2, false);
});

This is somewhat analog to binding the function and putting the bound function into the array, so the following would yield the same result:

// This just binds the function, effectively creating a new function,
// but does not execute it (yet)
var bound = window.removeEventListener.bind(window, 'event2', callback2, false);
unloaders.push(bound);

I like the first style better, but both are OK and actually not having a closure but a bound function might avoid some issues in some circumstances where the closure closes over too much stuff keeping it artificially alive. But that is usually a rare occurrence.

Anyway to finally call the functions stored in the array, you'd just have to iterate over it and then call the functions one after another.

for (let i = 0, len = unloaders.length; i < len; i++) {
  unloaders[i]();
}

But, to avoid that an exceptions exit the loop early, I suggest you wrap the calls in a try-catch.

for (let i = 0, len = unloaders.length; i < len; i++) {
  try {
    unloaders[i]();
  }
  catch (ex) {
    // Do something
  }
}

Actually, it might be preferable to call unloaders in the reverse order (last-in, first-out).

for (let i = unloaders.length - 1; i >= 0; i--) {
  try {
    unloaders[i]();
  }
  catch (ex) {
    // Do something
  }
}

The unload function from the other question has some more magic in it: It returns a function that lets you call the unloader you just registered at any time, properly removing it from the unloaders array when doing so. This is important for the unloadWindow function I also provided.

nmaier
  • 32,336
  • 5
  • 63
  • 78
  • Thanks Nils. The `bind` does not interfere with removal, correct? What is the benefit/difference of reverse order removal? Overall, it seems like a lot of work/code. An object array of `[{obj: window, event: 'event1', callback: callback1, capture: false}]` could be simpler!!!? – erosman Jun 29 '14 at 13:31
  • 1
    `bind` does not interfere removal, correct. The point of all this is to have an unloader facility that works with all types of tasks, not just event listeners. See the other question where I gave an example creating and removing a DOM element. [Here's another example use](https://github.com/nmaier/NoPluginBar/blob/master/main.js) – nmaier Jun 29 '14 at 13:49