CustomEvent in browser-JS is a rarely used feature, while it’s ubiquitous in it’s server-side counterpart. It looks like an elegant solution to dispatch state changes, redux-style.
Let’s see the good in this undervaluated feature
Good ol’ caniuse is positive :
We’ll need a IE 11 polyfill, which is fortunately simple enough (from mdn):
We can easily make helper functions like this :
The listener can unsubscribe itself as it should. It lacks things like a
listenOnce() shortcut, but that should be straightforward to implement as needed.
All’s well, but how fast is it?
The main drawback we read about over the web is the performance penalty of using too much event listeners in your app. However here, we’re not setting loads of handlers all over the place. It’s only using the
document element. That change things…
We’ll be testing 3 cases on 10000 iterations each. (complete code here)
All events are registered on
document global element. 10000 listeners are called when an event is dispatched.
10000 DOM nodes are created. Each one gets an element attached. We dispatch 10000 events and each listener gets its own.
Of course it’s hard to get a good measurement on a real world use case (3-4 listeners) because it’s sub-millisecond…
Overall, those results are great. Why so much hate over this function? It comes from a bad practice that frameworks like React and other Shadow DOM based projects tries to solve.
Each time something in the DOM that would change appearance is modified, the browser performs a
repaint (it’s more of a cascade of operations, but let’s keep it simple).
Except… not really.
To be efficient, the browser does not repaint until enough time has elapsed OR it’s queried for some DOM property and need to recalculate.
What does it means for our little listener? If it does ANY DOM query, it’s going to take ~30ms to complete (depending on page’s complexity).
CustomEvent mechanism is a great way to propagate, well, events… through your app. However, as always with vanilla JS, it’s easy to hurt performance greatly with no apparent reason.