- From: Joe Pea <notifications@github.com>
- Date: Fri, 15 May 2020 21:06:34 -0700
- To: whatwg/dom <dom@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <whatwg/dom/issues/484/629584604@github.com>
In case anyone stumbles here, I've been batched mutations [like this]9https://github.com/lume/lume/blob/32d368569af870e74ebdfac5e45f04f58466a961/src/core/Utility.ts#L16-L79)
Here's the code snippet from there:
```js
// TODO padd an options object to make it more clear what the args are.
function observeChildren(target: any, onConnect: any, onDisconnect: any, skipTextNodes: any) {
// TODO this Map is never cleaned, leaks memory. Maybe use WeakMap
const childObserver = createChildObserver(onConnect, onDisconnect, skipTextNodes)
childObserver.observe(target, {childList: true})
return childObserver
}
// NOTE: If a child is disconnected then connected to the same parent in the
// same turn, then the onConnect and onDisconnect callbacks won't be called
// because the DOM tree will be back in the exact state as before (this is
// possible thanks to the logic associated with weightsPerTarget).
function createChildObserver(onConnect: any, onDisconnect: any, skipTextNodes = false) {
return new MutationObserver(changes => {
const weightsPerTarget = new Map<any, Map<any, any>>()
// We're just counting how many times each child node was added and
// removed from the parent we're observing.
for (let i = 0, l = changes.length; i < l; i += 1) {
const change = changes[i]
if (change.type != 'childList') continue
let weights = weightsPerTarget.get(change.target)
if (!weights) weightsPerTarget.set(change.target, (weights = new Map()))
const {addedNodes} = change
for (let l = addedNodes.length, i = 0; i < l; i += 1)
weights.set(addedNodes[i], (weights.get(addedNodes[i]) || 0) + 1)
const {removedNodes} = change
for (let l = removedNodes.length, i = 0; i < l; i += 1)
weights.set(removedNodes[i], (weights.get(removedNodes[i]) || 0) - 1)
}
// NOTE, the destructuring inside the for..of header currently doesn't
// work due to a Buble bug, so we destructure inside the loop instead.
// https://github.com/Rich-Harris/buble/issues/182
// for (const [target, weights] of Array.from(weightsPerTarget)) {
for (const entry of Array.from(weightsPerTarget)) {
const [target, weights] = entry
// for (const [node, weight] of Array.from(weights)) {
for (const entry of Array.from(weights)) {
const [node, weight] = entry
if (skipTextNodes && (node instanceof Text || node instanceof Comment)) continue
// If the number of times a child was added is greater than the
// number of times it was removed, then the net result is that
// it was added, so we call onConnect just once.
if (weight > 0 && typeof onConnect == 'function') onConnect.call(target, node)
// If the number of times a child was added is less than the
// number of times it was removed, then the net result is that
// it was removed, so we call onDisconnect just once.
else if (weight < 0 && typeof onDisconnect == 'function') onDisconnect.call(target, node)
// If the number of times a child was added is equal to the
// number of times it was removed, then it was essentially left
// in place, so we don't call anything.
}
}
})
}
```
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/484#issuecomment-629584604
Received on Saturday, 16 May 2020 04:06:47 UTC