- From: Joe Pea <notifications@github.com>
- Date: Fri, 26 Aug 2022 17:17:28 -0700
- To: whatwg/dom <dom@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <whatwg/dom/issues/1105/1229056530@github.com>
# Userland Solution Currently, MOs run all at once per target, which is highly irrepresentative of the order in which mutations happened in the DOM. The end user has two options, both of which get more complicated: 1. Use a single MutationObserver root node of the current tree. 2. Implement some additional tracking across all MutationObservers on individual targets Here is an example of option 2 in userland: https://codepen.io/trusktr/pen/ExEBxmw/401b4869c60721e0fca18840036cbdee?editors=0010 # Possible Ideal Solutions (in the engine) ## 1 MutationObserver I think the ideal solution would be for the browser engine to intelligently split MO changesets into chunks, and call them in the correct order (by calling MO callbacks for a single target one or more times) within the MO microtask, such that we can guarantee that each for loop in any callback is always iterating in the correct order relative to the whole tree in which the MutationObservers are observing. This would eliminate the need for end users to write the complicated code required for the userland solutions. ## 2 Mutation Events Fix DOM Mutation Events (make a new one with different names perhaps, or a new API that is similar to events). ------- Finally, compare how drastically complicated this code, ```js const connected = new Set const disconnected = new Set let scheduled = false class XEl extends HTMLElement { connectedCallback() { this.o = new MutationObserver(changes => { for (const change of changes) { console.log('--- change', change.target) for (const child of change.addedNodes) { console.log('track added child', child) connected.add(child) } for (const child of change.removedNodes) { console.log('track removed child', child) disconnected.add(child) } } if (!scheduled) { scheduled = true queueMicrotask(() => { console.log('--------------- MICROTASK MO') scheduled = false const allNodes = new Set([...connected, ...disconnected]) for (const child of allNodes) { if (child.parentElement) { if (disconnected.has(child)) console.log('child removed:', child) if (connected.has(child)) console.log('child added:', child) } else { if (connected.has(child)) console.log('child added:', child) if (disconnected.has(child)) console.log('child removed:', child) } } connected.clear() disconnected.clear() }) } }) this.o.observe(this, {childList: true}) } disconnectedCallback() { this.o.disconnect() } } customElements.define('x-el', XEl) setTimeout(() => { queueMicrotask(() => console.log('--------------- MICROTASK before')) const t = three t.remove() one.append(t) queueMicrotask(() => console.log('--------------- MICROTASK after')) }, 1000) ``` is compared to DOM Mutation Events code: ```js const connected = new Set const disconnected = new Set let scheduled = false const events = new Set() class XEl extends HTMLElement { lastConnected = new Set childConnected = (event) => { if (event.target.parentElement !== this) return this.lastConnected.add(event.target) console.log('child added:', this, event.target) } childDisconnected = (event) => { if (!this.lastConnected.has(event.target)) return this.lastConnected.delete(event.target) console.log('child removed:', this, event.target) } connectedCallback() { for (const child of this.children) this.lastConnected.add(child) this.addEventListener('DOMNodeInserted', this.childConnected) this.addEventListener('DOMNodeRemoved', this.childDisconnected) } disconnectedCallback() { this.removeEventListener('DOMNodeInserted', this.childConnected) this.removeEventListener('DOMNodeRemoved', this.childDisconnected) } } customElements.define('x-el', XEl) setTimeout(() => { queueMicrotask(() => console.log('--------------- MICROTASK before')) const t = three t.remove() one.append(t) queueMicrotask(() => console.log('--------------- MICROTASK after')) }, 1000) ``` And that's not even simple enough. We didn't need to make a complicated API (MutationObserver) in order to have a deferred-batched event system. -- Reply to this email directly or view it on GitHub: https://github.com/whatwg/dom/issues/1105#issuecomment-1229056530 You are receiving this because you are subscribed to this thread. Message ID: <whatwg/dom/issues/1105/1229056530@github.com>
Received on Saturday, 27 August 2022 00:17:41 UTC