简体   繁体   English

DOM Mutation Observers比DOM Mutation事件慢吗?

[英]Are DOM Mutation Observers slower than DOM Mutation Events?

The following code utilize DOM Mutation Event DOMNodeInserted to detect the existence of the body element and wrap its innerHTML into a wrapper. 以下代码利用DOM Mutation Event DOMNodeInserted来检测body元素的存在并将其innerHTML包装到包装器中。

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>
        function DOMmanipulation() {
            if (document.body) {
                document.removeEventListener('DOMNodeInserted', DOMmanipulation);
                // DOM manipulation start
                document.body.innerHTML = '<div class="wrapper">' + document.body.innerHTML + '</div>';
                // DOM manipulation end
            }
        }
        document.addEventListener('DOMNodeInserted', DOMmanipulation);
    </script>
</head>
<body>
    <p>Lorem ipsum dolor sit amet.</p>
</body>
</html>

And despite the success of the wrapping, there is an error shows that a node was not found. 尽管包装成功,但是有一个错误表明找不到节点。 This answer of a question explained that it is because when jQuery had been loaded, it added a div element into the body to do some tests, but it failed to remove that div element because that element has been wrapped into the wrapper so that it's not a child element of body anymore. 这个问题的答案解释说,这是因为当jQuery被加载时,它在主体中添加了一个div元素来进行一些测试,但它无法删除那个div元素,因为该元素已被包装到包装器中,所以它不是身体的儿童元素了。

The above experiment tells us that DOMNodeInserted event is faster than jQuery's tests because jQuery's test element ( div ) got wrapped before it can be removed by jQuery. 上面的实验告诉我们DOMNodeInserted事件比jQuery的测试更快,因为jQuery的测试元素( div )在被jQuery删除之前被包装。




Now the following code can achieve the same manipulation, and it's using the newly introduced DOM Mutation Observers. 现在,以下代码可以实现相同的操作,并且它使用新引入的DOM Mutation Observers。 As of this time (2012-07-11), it works only on Chrome 18 and higher. 截至此时(2012-07-11),它仅适用于Chrome 18及更高版本。

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>
        var observer = new WebKitMutationObserver(function() {  
            if (document.body) {
                observer.disconnect();
                // DOM manipulation start
                document.body.innerHTML = '<div class="wrapper">' + document.body.innerHTML + '</div>';
                // DOM manipulation end
            }
        });
        observer.observe(document, { subtree: true, childList: true });
    </script>
</head>
<body>
    <p>Lorem ipsum dolor sit amet.</p>
</body>
</html>

This codes didn't produce any error. 此代码不会产生任何错误。 That means jQuery is faster than DOM Mutation Observers, so it was able to remove its test element ( div ) before that element can be wrapped into the wrapper. 这意味着jQuery比DOM Mutation Observers更快,因此它可以在将该元素包装到包装器之前删除其测试元素( div )。




From the above two experiments, we find that when it comes to execution speed: 从以上两个实验中,我们发现在执行速度方面:

  • DOM Mutation Events > jQuery's tests DOM Mutation Events> jQuery的测试
  • jQuery's tests > DOM Mutation Observers jQuery的测试> DOM Mutation Observers

Can this result appropriately prove that DOM Mutation Observers is slower than DOM Mutation Events? 这个结果能否恰当地证明DOM Mutation Observers比DOM Mutation Events慢?

DOM Mutation Observers, are not intended to be faster than DOM Mutation Events. DOM Mutation Observers并不比DOM Mutation Events更快。 Rather they are intended to be more efficient and safer. 相反,它们旨在更高效,更安全。

The basic gist of the difference is that DOM Mutation Events fire whenever there is a change. 差异的基本要点是DOM Mutation Events会在发生变化时触发。 So this code for example would create a callback loop, that will ultimately crash the browser. 因此,此代码将创建一个回调循环,最终将导致浏览器崩溃。

document.addEventListener('DOMNodeInserted', function() {
    var newEl = document.createElement('div');
    document.body.appendChild(newEl);
});

The fact that they are called in this fashion and so often also has a significant effect on the browser, as it forces an interrupt between the browsers recalculate style, reflow and repaint cycle or worse forces the browser to recalculate styles, reflow and repaint on every callback. 以这种方式调用它们的事实往往也会对浏览器产生重大影响,因为它会强制浏览器之间的中断重新计算样式,重排和重新绘制循环,或者更糟糕的是迫使浏览器重新计算样式,重新回流并重新绘制每个样式打回来。 The problem is further exasperated by the fact that other code maybe executing that makes further changes to the DOM, which will continue to be interrupted by your callback. 由于其他代码可能正在执行而对DOM进行进一步更改的事实进一步加剧了这个问题,这将继续被回调中断。

What's more is that because events propagate in the same way as normal DOM Events, you're going to start hearing changes on elements that you might not care about or didn't account for in your code. 更重要的是,因为事件以与普通DOM事件相同的方式传播,您将开始听到您可能不关心或未在代码中考虑的元素的更改。 So the whole mechanism of DOM Mutation Events can become troublesome to manage fairly quickly. 因此,DOM Mutation事件的整个机制很快就会变得很麻烦。

DOM Mutation Observers counteract these problems by, as the name suggests observing changes to the DOM and providing you with a report of all the changes that took place from from the start of the change. DOM突变观察者通过观察DOM的变化并向您提供从变更开始时发生的所有变化的报告来抵消这些问题。 This is a much better situation to be in as it allows the browsers to notify you at a time that makes sense, for example when the document is idle and all other JavaScript that could make further changes has finished executing, or before the browser restarts the recalc / repaint cycle, so it can apply any changes you make, without having to repeat the cycle shortly after. 这是一个更好的情况,因为它允许浏览器在有意义的时间通知您,例如当文档空闲且所有其他可以进行进一步更改的JavaScript已完成执行时,或者在浏览器重新启动之前recalc / repaint循环,因此它可以应用您所做的任何更改,而不必在之后不久重复循环。

It also makes it easier for you to manage, because you can scan through all the changed elements to find what you're looking for, instead of writing lots of case handling code for stuff you don't care about, as was the situation with Mutation Events. 它还使您更容易管理,因为您可以扫描所有更改的元素以找到您要查找的内容,而不是为您不关心的内容编写大量案例处理代码,就像突变事件。 And more importantly its only going to call it once, so you don't need to worry that any further changes are going to effect the elements ie they are no longer in changing state, they have changed. 更重要的是它只会调用一次,所以你不必担心任何进一步的变化会影响元素,即它们不再处于改变状态,它们已经改变了。

So in answer to your question, DOM Mutation Observers are slower because they waited for jQuery to finish its manipulation of the DOM before it notified you of what jQuery changed. 因此,在回答您的问题时,DOM Mutation Observers更慢,因为他们在通知您jQuery更改之前等待jQuery完成对DOM的操作。 Which for the reason explained above and your example, proves it is safer more efficient solution ( you no longer cause an error), and you didn't really care that jQuery added something to the DOM because it would have removed it shortly after. 由于上面解释的原因和您的示例,证明它是更安全更有效的解决方案(您不再导致错误),并且您并不真正关心jQuery为DOM添加了一些东西,因为它很快就会删除它。 With Observers you would have received a report detailing the jQuery element being added and removed. 使用Observers,您将收到一份报告,详细说明要添加和删除的jQuery元素。

This is still a bit troublesome however because you have to figure out what actually happened by matching up elements with all the changes that took place. 这仍然有点麻烦,因为你必须通过匹配元素与发生的所有变化来弄清楚实际发生了什么。 The reality is that as far as you're concerned nothing happened ( the same element was added and removed ) so nothing has actually changed in the structure of the DOM. 实际情况是,只要你担心什么都没发生(添加和删除相同的元素),所以在DOM的结构中没有任何实际改变。 To help with this there is a little library called MutationSummary: 为了帮助解决这个问题,有一个名为MutationSummary的小库:

http://code.google.com/p/mutation-summary/ http://code.google.com/p/mutation-summary/

That calculates the net effect of the changes and only calls your callback passing in those changes. 这会计算更改的净效果,并仅调用您的回调传递这些更改。 So in your case your callback would not have been called at all, because the net effect of the change was zero. 因此,在您的情况下,根本不会调用您的回调,因为更改的净效果为零。

Eg for the following you will only get one change. 例如,对于以下内容,您只能进行一次更改。 The body style was changed to left: 1000px. 体型改为左:1000px。 Even though I changed it in 1000 increments. 即使我以1000增量更改它。 The net effect of the change is only the difference between its initial value and its final one. 变化的净效应仅是其初始值与最终值之间的差异。

function moveBody() {
    for (var i = 0; i < 1000; i++) document.body.style.left = i + 'px';
}
moveBody();

The simple answer is that mutation observers are asynchronous. 简单的答案是变异观察者是异步的。 They are sent whenever the engine feels like it, some time after the change has taken place and in some cases after a great many changes have taken place. 只要发动机感觉它,发生变化后的某个时间以及在发生了很多变化之后的某些情况下,它们就会被发送。 That may be long after a DOM mutation event listener would have notified you, but meanwhile the engine has been free to get its work done without having to constantly create and bubble events for every piddling DOM change. 这可能是在DOM突变事件监听器通知您之后很长时间,但同时引擎可以自由地完成其工作,而无需为每个捣乱的DOM更改不断创建和冒泡事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM