Hi, One of the major use cases for MutationObserver is all kinds of libraries that either shim APIs or provide intrinsic modifications to DOM experience.
Examples of such libraries may be: * A library that provides Date/Time pickers only caring about <input type="date|time"> * A library that extends behavior of a particular web component from outside * A library that extends behavior of common elements with particular attributes * our l10n library only looks for element with data-l10n-id|data-l10n-args * a resource API shim may be looking for <links> with a given attribute Unfortunately, at the moment, MutationObserver API makes it particularly hard for libraries to narrow down the scope of elements that are monitored by them which results in three things: *) Higher CPU/power cost of running a MutationObserver on a DOM tree *) More noise inside the MutationObserver callback *) Requirement for fairly sophisticated filtering to get the right elements The reason for so much noise is that there's no way to instrument MutationObserver to notice only specific elements. The only filtering can be done for attributes, but for node adding/removing MutationObserver reports *all* elements and often in form of a DOMFragment which has to be filtered. Example from our l10n library: const observerConfig = { attributes: true, characterData: false, childList: true, subtree: true, attributeFilter: ['data-l10n-id', 'data-l10n-args'] }; var mo = new MutationObserver(onMutations); mo.observe(this.doc, observerConfig); function onMutations(mutations) { const targets = new Set(); for (let mutation of mutations) { switch (mutation.type) { case 'attributes': targets.add(mutation.target); break; case 'childList': for (let addedNode of mutation.addedNodes) { if (addedNode.nodeType === addedNode.ELEMENT_NODE) { if (addedNode.hasAttribute('data-l10n-id')) { targets.add(addedNode); } if (addedNode.childElementCount) { element.querySelectorAll('[data-l10n-id]').forEach( elem => targets.add(elem)); } } } break; } } if (targets.size === 0) { return; } translateElements(targets); } Proposal: const observerConfig = { attributes: true, attributeFilter: ['data-l10n-id', 'data-l10n-args'] querySelector: '*[data-l10n-id]' }; var mo = new MutationObserver(onMutations); mo.observe(this.doc, observerConfig); function onMutations(mutations) { const targets = new Set(); for (let mutation of mutations) { switch (mutation.type) { case 'attributes': targets.add(mutation.target); break; case 'childList': for (let addedNode of mutation.addedNodes) { targets.add(addedNode); } break; } } if (targets.size === 0) { return; } translateElements(targets); } And it's not only about cleaner code. In Firefox OS' Settings app, our onMutations is fired hundreds of times as we construct DOM dynamically, while l10n cares about 70 elements out of those. I believe that there's a substantial value in extending MutationObserver API to help with such filtering for all scenarios listed at the top and many similar ones. Would it be possible to do within MutationObserver API or would it be material for a separate API? Thanks, zb. _______________________________________________ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform