1

I'm trying to figure out the best way to react to changes in the DOM.

I've read similar posts about this, such as this one and this one and neither of them make it explicitly clear when to use Mutation Observers and when to use window.addEventListener("onresize", callback). Are Mutation Observers more efficient than window.addEventListener("onresize", callback) even if the resize event is throttled?

I've included this under the CSS3 tag because it looks like there were, in 2012, some neat CSS tricks that triggered custom resize events and I was wondering if there have been any innovations since then.

Community
  • 1
  • 1
user5508297
  • 805
  • 2
  • 9
  • 24

2 Answers2

2

Those two are different tools to solve different problems. Mutation observers are used to react to the changes in DOM. Say you want to write a javascript function that replaces one word into another on the whole page, without end user noticing anything. You could use setInterval here, but there's a risk of "flashing" content as it loads from the server ( or asynchronous AJAX call), unless you set the interval to a very small value, in which case it becomes a very resource intensive solution.

So instead you could write a mutation observer, which would get called every time there's a change in the DOM, which includes the page rendering or javascript adding/removing/modifying HTML elements down the line. A client-side A/B testing tool I once wrote used those to catch changes in DOM and process them in the fastest way possible.

Adding listener to onresize event does just that - it gets called when the browser window is resized, regardless of DOM state at that point. So these two are not really interchangeable. Mutation observers can get quite "expensive" resource-wise on heavier pages, so you might have to implement throttling there. What you need depends on the specific case that you're dealing with, no way to answer that for sure.

Tadas Paplauskas
  • 1,863
  • 11
  • 15
  • Thanks for your answer @Tadas Paplauskas. If I have a Mutation Observer that is observing the width attribute of an element and since, it's percentage based, I know that it will also change on window resize which one should I use? – user5508297 Aug 04 '16 at 17:32
  • If you only care about resizing, and it sounds like it, then definitely go with onresize event - it's designed exactly for cases like yours and should offer better performance. – Tadas Paplauskas Aug 04 '16 at 17:34
  • MutationObserver will only catch that if an actual *html attribute* value is changing, not just a calculated width based on CSS rules. – wOxxOm Aug 04 '16 at 17:39
  • @wOxxOm I realise that - I am referring to cases where the element's width/height attribute changes (not just its clientWidth/Height etc.). – user5508297 Aug 04 '16 at 18:11
1

Besides handling two entirely different and usually unrelated tasks, their timing is different.

MutationObserver callback is executed as a microtask during current event when no changes have been painted on screen yet. Since Javascript is single-threaded, the callback execution blocks further DOM parsing and the entire JS engine, so you'd want to make it very fast (I'm afraid, most wrapper libraries aren't, because of their versatility) and avoid observing the entire document while a complex page is being loaded as the callback may be called hundreds of times with lots of addedNodes in each mutation.

Events ("resize" event included) are added to the internal event queue and are processed when the current event queue has been completely processed and changes painted. For example, setTimeout(callback, 0), which creates a normal event task, may postpone the callback execution during a complex page load for 100-1000ms.

So, use MutationObserver only if you really want to change something before it's painted to make your changes seamlessly integrated with the page. And of course, MutationObserver will only catch a change if an actual html attribute value has been changed or a node added/removed/changed, not just a calculated width based on CSS rules.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136