2012-07-11 22 views
8

次のコードでは、DOM突然変異イベントDOMNodeInsertedを使用してbody要素の存在を検出し、そのinnerHTMLをラッパーにラップします。DOM突然変異観察者はDOM突然変異イベントよりも遅いですか?

<!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> 

そして、ラッピングが成功したにもかかわらず、ノードが見つからないというエラーが表示されます。 This answerは、jQueryがロードされたときに本体にdiv要素を追加していくつかのテストを実行したが、div要素を削除できなかったため、その要素がラッパーにラップされていないため子どもの身体の要素。

上記の実験では、jQueryのテスト要素(div)がjQueryで削除される前にラップされているため、DOMNodeInsertedイベントはjQueryのテストより高速であることがわかりました。




今、次のコードは、同じ操作を実現することができ、それが新たに導入されたDOM変更オブザーバーを使用しています。今回(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変異イベント> jQueryのテスト
  • jQueryのテスト> DOM変異オブザーバ

この結果は、DOM変異突然変異体がDOM突然変異イベントよりも遅いことを適切に証明できますか?

答えて

24

DOM変異オブザーバは、DOM突然変異イベントより高速であることを意図していません。むしろ、より効率的で安全なものにすることを意図しています。

違いの基本的なところは、DOM変異イベントは変更があるたびに発生するということです。たとえば、このコードはコールバックループを作成し、最終的にはブラウザをクラッシュさせます。

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

彼らはこのように呼ばれているという事実と、それはブラウザ間の割り込みを強制されるので、多くの場合も、ブラウザ上で大きな影響を与えるには、スタイル、リフローを再計算し、再計算するサイクルも悪くも力にブラウザを再描画しますスタイル、リフロー、およびすべてのコールバックでの再ペイント。この問題は、他のコードが実行されてDOMにさらに変更を加える可能性があり、コールバックによって中断され続けるという事実によってさらに拍車をかけます。しかも

イベントは、通常のDOMイベントと同じように伝播するので、あなたが気にしないことがありますか、あなたのコードでは考慮されませんでした要素の変化を聞いて開始するつもりだということです。したがって、DOM突然変異イベントの全体機構は、かなり迅速に管理するのに面倒になる可能性があります。

DOM変異オブザーバは、DOMの変更を観察し、変更の開始時から行われたすべての変更のレポートを提供することを示唆しているため、これらの問題に対処しています。たとえば、ドキュメントがアイドル状態で、さらに変更を加えることができる他のすべてのJavaScriptの実行が終了したときや、ブラウザがブラウザを再起動する前など、ブラウザが一瞬にあなたに通知することができるので、これははるかに良い状況です。 recalc/repaintサイクルを使用しているため、変更を適用することができます。サイクルをやり直す必要はありません。

あなたが探しているものを見つけるために、変更されたすべての要素をスキャンすることができますので、それはまたのように、代わりにあなたが気にしないもののためのコードを扱う例をたくさん書くの、それが簡単にあなたが管理できるようになり突然変異イベントの状況でした。さらに重要なのは、それを一度だけ呼び出すことだから、それ以上の変更が要素に影響を与える、つまりもはや状態が変わっていない、変更されていることを心配する必要はありません。

あなたの質問に答えて、DOM変異オブザーバは、jQueryが変更されたものを通知する前にjQueryがDOMの操作を完了するのを待っているため、処理が遅くなります。前述の理由とあなたの例で説明したように、より効率的なソリューションがより安全であることが証明されています(エラーは発生しなくなりました)。jQueryがDOMに何かを追加したのは気にしませんでした。 Observersを使用すると、追加および削除されるjQuery要素の詳細が表示されます。あなたが実際に行われた変更をすべての要素を照合することによって何が起こったのか把握する必要があるため

しかし、これはまだ少し面倒です。現実は、何も起こっていない(同じ要素が追加され、削除された)ため、DOMの構造が実際に変更されていないということです。変化した場合の影響額を計算し、変更のみを渡し、あなたのコールバックを呼び出し

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

:これを支援するためにMutationSummaryと呼ばれる小さなライブラリがあります。あなたのケースでは、変更の正味の効果がゼロだったので、コールバックはまったく呼び出されませんでした。

など。次の場合、1つの変更だけが得られます。ボディスタイルが左:1000pxに変更されました。私は1000単位でそれを変更しましたが。変更の正味の効果は、初期値と最終値の差のみです。

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

ありがとう@AshHeskesと素敵な説明!最後に私はその実行の原則を理解しています。 –

6

単純な答えは、突然変異の観察者は非同期であるということです。彼らは、エンジンがそのように感じるたびに、変更が行われた後のある時間に、そしていくつかのケースでは、非常に多くの変更が行われた後に送信されます。それは、DOM変異イベントリスナーがあなたに通知した後には長いかもしれませんが、一方、エンジンは、いたずらに起こるDOM変更ごとに常にイベントを作成しバブルする必要なしに、その作業を自由に行えます。

+0

ありがとうNartowicz! –

関連する問題