Re: [w3c/webcomponents] Element.prototype.connectedCallback, et al. (#629)

Here's `childConnectedCallback` implemented on `Element.prototype.connectedCallback` (compare with the above `MutationObserver` implementation):

```js
Element.prototype.connectedCallback = function() {
  if (this.parentElement && this.parentElement.childConnectedCallback)
    this.parentElement.childConnectedCallback(this)
}
```

This is much simpler!

Also (at least in Chrome), the order of `MutationRecords` do not always fire in the same order as the things that trigger them. This sort of problem is completely avoided with the `Element.prototype.connectedCallback` implementation.

For reference, I discovered that using a single global MutationObserver rather than one per element fixes the problem of MutationRecord callbacks happening out of order. After changing my MutationObserver implementation to the following I solved a bug caused by out-of-order callbacks:

```js
let childObservationHandlers = null
let childObserver = null
function observeChildren(ctx, onConnect, onDisconnect) {
    if (!childObservationHandlers) childObservationHandlers = new Map
    if (!childObserver) childObserver = createChildObserver()
    childObservationHandlers.set(ctx, {onConnect, onDisconnect})
    childObserver.observe(ctx, { childList: true })
    return true
}
function createChildObserver() {
    return new MutationObserver(async (changes) => {
        const weightsPerTarget = new Map

        console.log('changes', changes, performance.now())

        for (const change of changes) {
            if (change.type != 'childList') continue

            if (!weightsPerTarget.has(change.target))
                weightsPerTarget.set(change.target, new Map)

            const weights = weightsPerTarget.get(change.target)

            for (const addedNode of change.addedNodes)
                weights.set(addedNode, (weights.get(addedNode) || 0) + 1)

            for (const removedNode of change.removedNodes)
                weights.set(removedNode, (weights.get(removedNode) || 0) - 1)
        }

        for (const [target, weights] of weightsPerTarget) {
            const {onConnect, onDisconnect} = childObservationHandlers.get(target)

            for (const [node, weight] of weights) {
                if (weight > 0 && typeof onConnect == 'function')
                    onConnect.call(target, node)
                else if (weight < 0 && typeof onDisconnect == 'function')
                    onDisconnect.call(target, node)
            }
        }
    })
}
```

And... now it is even *more* complicated than the 3-line `Element.prototype.connectedCallback` version.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/629#issuecomment-285921048

Received on Sunday, 12 March 2017 04:15:06 UTC