MutationObserver 给出的 MutationRecord 保证是有序的吗?

问题描述 投票:0回答:1

我很好奇 MutationObserver 接收到的一批突变是否按顺序返回。

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type); // are these in order?
  });    
});

谢谢!

javascript browser mutation-observers
1个回答
1
投票

不。不能保证它们是有序的,这让事情变得非常困难。

看一下这个例子,例如:

https://codepen.io/trusktr/pen/OJveVbv/d7f4cc48f8fa3b7462ae8043157ba05d

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 for target', change.target.id)
                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() // queue mutation for two
    one.append(t) // queue mutation for one
    
    t.remove() // queue mutation for one
    two.append(t) // queue mutation for two
    
    t.remove() // queue mutation for two
    one.append(t) // queue mutation for one
    
    t.remove() // queue mutation for one
    two.append(t) // queue mutation for two
    
    queueMicrotask(() => console.log('--------------- MICROTASK after'))
}, 1000)
<x-el id="one">
    one
    <x-el id="two">
        two
        <x-el id="three">
            three
        </x-el>
    </x-el>
</x-el>

请注意,在控制台输出中,首先循环一个父元素的所有记录,然后循环另一个父元素的所有记录。

这与实际运行的代码完全不同,其中它在父级一和父级二之间交替。


顺便说一句,与 DOM Mutation Events 相比,Mutation Observer 非常难以使用。我坚信,可以创建一个类似于 Mutation Events 的、更直观、不影响性能的 API 版本,而不是 MutationObserver 的 childList API。

有关开发人员体验的 MutationObserver 复杂性与 Mutation Events 简单性的更多详细信息:

https://github.com/whatwg/dom/issues/1105

如果您同意,请表达对更简单 API 的需求!

© www.soinside.com 2019 - 2024. All rights reserved.