[英]Are DOM Mutation Observers slower than DOM Mutation Events?
以下代碼利用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>
盡管包裝成功,但是有一個錯誤表明找不到節點。 這個問題的答案解釋說,這是因為當jQuery被加載時,它在主體中添加了一個div
元素來進行一些測試,但它無法刪除那個div
元素,因為該元素已被包裝到包裝器中,所以它不是身體的兒童元素了。
上面的實驗告訴我們DOMNodeInserted
事件比jQuery的測試更快,因為jQuery的測試元素( div
)在被jQuery刪除之前被包裝。
現在,以下代碼可以實現相同的操作,並且它使用新引入的DOM Mutation Observers。 截至此時(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>
此代碼不會產生任何錯誤。 這意味着jQuery比DOM Mutation Observers更快,因此它可以在將該元素包裝到包裝器之前刪除其測試元素( div
)。
從以上兩個實驗中,我們發現在執行速度方面:
這個結果能否恰當地證明DOM Mutation Observers比DOM Mutation Events慢?
DOM Mutation Observers並不比DOM Mutation Events更快。 相反,它們旨在更高效,更安全。
差異的基本要點是DOM Mutation Events會在發生變化時觸發。 因此,此代碼將創建一個回調循環,最終將導致瀏覽器崩潰。
document.addEventListener('DOMNodeInserted', function() {
var newEl = document.createElement('div');
document.body.appendChild(newEl);
});
以這種方式調用它們的事實往往也會對瀏覽器產生重大影響,因為它會強制瀏覽器之間的中斷重新計算樣式,重排和重新繪制循環,或者更糟糕的是迫使瀏覽器重新計算樣式,重新回流並重新繪制每個樣式打回來。 由於其他代碼可能正在執行而對DOM進行進一步更改的事實進一步加劇了這個問題,這將繼續被回調中斷。
更重要的是,因為事件以與普通DOM事件相同的方式傳播,您將開始聽到您可能不關心或未在代碼中考慮的元素的更改。 因此,DOM Mutation事件的整個機制很快就會變得很麻煩。
DOM突變觀察者通過觀察DOM的變化並向您提供從變更開始時發生的所有變化的報告來抵消這些問題。 這是一個更好的情況,因為它允許瀏覽器在有意義的時間通知您,例如當文檔空閑且所有其他可以進行進一步更改的JavaScript已完成執行時,或者在瀏覽器重新啟動之前recalc / repaint循環,因此它可以應用您所做的任何更改,而不必在之后不久重復循環。
它還使您更容易管理,因為您可以掃描所有更改的元素以找到您要查找的內容,而不是為您不關心的內容編寫大量案例處理代碼,就像突變事件。 更重要的是它只會調用一次,所以你不必擔心任何進一步的變化會影響元素,即它們不再處於改變狀態,它們已經改變了。
因此,在回答您的問題時,DOM Mutation Observers更慢,因為他們在通知您jQuery更改之前等待jQuery完成對DOM的操作。 由於上面解釋的原因和您的示例,證明它是更安全更有效的解決方案(您不再導致錯誤),並且您並不真正關心jQuery為DOM添加了一些東西,因為它很快就會刪除它。 使用Observers,您將收到一份報告,詳細說明要添加和刪除的jQuery元素。
這仍然有點麻煩,因為你必須通過匹配元素與發生的所有變化來弄清楚實際發生了什么。 實際情況是,只要你擔心什么都沒發生(添加和刪除相同的元素),所以在DOM的結構中沒有任何實際改變。 為了幫助解決這個問題,有一個名為MutationSummary的小庫:
http://code.google.com/p/mutation-summary/
這會計算更改的凈效果,並僅調用您的回調傳遞這些更改。 因此,在您的情況下,根本不會調用您的回調,因為更改的凈效果為零。
例如,對於以下內容,您只能進行一次更改。 體型改為左:1000px。 即使我以1000增量更改它。 變化的凈效應僅是其初始值與最終值之間的差異。
function moveBody() {
for (var i = 0; i < 1000; i++) document.body.style.left = i + 'px';
}
moveBody();
簡單的答案是變異觀察者是異步的。 只要發動機感覺它,發生變化后的某個時間以及在發生了很多變化之后的某些情況下,它們就會被發送。 這可能是在DOM突變事件監聽器通知您之后很長時間,但同時引擎可以自由地完成其工作,而無需為每個搗亂的DOM更改不斷創建和冒泡事件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.