观察目标节点上尚不存在的突变

Don*_*n P 19 javascript mutation-observers

是否有可能在DOM节点上观察到尚不存在的突变?

例:

我的应用程序在某些时候创建了一个div : <div id="message" data-message-content="foo" data-message-type="bar" />.

我想留意这个div的创造和变化.

var mutationObserver = new MutationObserver(function(mutations){
  // Some code to handle the mutation.
});

mutationObserver.observe(
    document.querySelector('#message'),
        { 
            attributes: true, 
            subtree: true, 
            childList: true, 
            characterData: false 
        }
    );
);
Run Code Online (Sandbox Code Playgroud)

现在这会返回一个错误,因为它#message是null(尚未创建div).

Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.

一个明显的解决方案是观察body和检查是否有任何突变div#Message,但这似乎是一个坏主意/或可能不利于性能.

wOx*_*xOm 44

只能观察现有节点.

但不要担心,因为与枚举所有突变的添加节点相比,getElementById的速度非常快,等待元素出现将不会产生任何负担,正如您将在Devtools - > Profiler面板中看到的那样.

function waitForAddedNode(params) {
    new MutationObserver(function(mutations) {
        var el = document.getElementById(params.id);
        if (el) {
            this.disconnect();
            params.done(el);
        }
    }).observe(params.parent || document, {
        subtree: !!params.recursive,
        childList: true,
    });
}
Run Code Online (Sandbox Code Playgroud)

用法:

waitForAddedNode({
    id: 'message',
    parent: document.querySelector('.container'),
    recursive: false,
    done: function(el) {
        console.log(el);
    }
});
Run Code Online (Sandbox Code Playgroud)

始终使用devtools探查器并尝试使观察者回调消耗不到CPU时间的1%.

  • 尽可能观察未来节点的直接父节点(subtree: false)
  • 在MutationObserver回调中使用getElementById,getElementsByTagName和getElementsByClassName,避免使用querySelector,尤其是极慢的querySelectorAll.
  • 如果querySelectorAll在MutationObserver回调中绝对不可避免,首先执行querySelector检查,平均来说这样的组合会快得多.
  • 不要使用像forEach,filter等需要在MutationObserver回调中进行回调的数组方法,因为与经典for (var i=0 ....)循环相比,Javascript函数调用是一项昂贵的操作,并且MutationObserver回调可能每秒触发数十次,数百次或数千次addedNodes在复杂的现代页面上的每批突变.
  • 不要像MutationObserver回调中那样使用慢速ES2015循环,for (v of something)除非你进行反编译,结果代码的运行速度与经典for循环一样快.

  • 好吧,这是我在这里得到的最深入(关于性能)的答案之一。谢谢! (5认同)
  • 这是一个巧妙的方法,因为您不依赖于突变属性(我遇到了困难),而只是每次检查所需的元素是否存在。有点像超时轮询。不过依赖于具有 id 的元素... (2认同)