2012-07-11 17 views
8

Poniższy kod wykorzystuje zdarzenie mutacji DOM DOMNodeInserted w celu wykrycia istnienia elementu body i zawinięcia jego innerHTML w opakowanie.Czy obserwatory mutacji DOM działają wolniej niż zdarzenia mutacji 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> 

Mimo pomyślnego zawinięcia występuje błąd informujący, że węzeł nie został znaleziony. This answer pytania wyjaśnił, że to dlatego, że po załadowaniu jQuery dodano element div do ciała, aby wykonać pewne testy, ale nie udało się usunąć tego elementu div, ponieważ ten element został zawinięty w opakowanie, aby nie był element dziecka w ciele.

Powyższy eksperyment mówi, że zdarzenie DOMNodeInserted jest szybsze niż testy jQuery, ponieważ element testowy jQuery (div) został zawinięty, zanim zostanie usunięty przez jQuery.




Teraz następujący kod może osiągnąć ten sam manipulacji, i to przy użyciu nowo wprowadzonych obserwatorów DOM mutacji. Od tego czasu (2012-07-11) działa tylko w przeglądarce Chrome 18 i nowszych.

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

Kod ten nie spowodował błędu. Oznacza to, że jQuery jest szybszy niż obserwatory mutacji DOM, więc mógł usunąć swój element testowy (div), zanim ten element zostanie zawinięty w opakowanie.




Z powyższych dwóch doświadczeń, możemy stwierdzić, że jeśli chodzi o szybkość wykonywania:

  • DOM mutacji Wydarzenia > testy jQuery za
  • testów jQuery > Obserwatorzy mutacji DOM

Czy ten wynik może odpowiednio udowodnić, że obserwatory mutacji DOM są wolniejsze niż zdarzenia mutacji DOM?

Odpowiedz

24

Obserwatorzy mutacji DOM nie mają być szybsze niż zdarzenia mutacji DOM. Raczej mają być bardziej wydajne i bezpieczniejsze.

Podstawową zaletą tej różnicy jest to, że zdarzenia mutacji DOM są uruchamiane w przypadku każdej zmiany. Tak więc ten kod na przykład tworzy pętlę zwrotną, która ostatecznie zawiesi przeglądarkę.

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

fakt, że są one nazywane w ten sposób i tak często również ma znaczący wpływ na przeglądarce, ponieważ wymusza przerwanie między przeglądarkami przeliczyć styl, reflow i przemalować cyklu lub gorzej zmusza przeglądarkę przeliczyć style, reflow i repaint na każdym wywołaniu zwrotnym. Problem jest jeszcze bardziej podrażniony faktem, że może być wykonywany inny kod, który powoduje dalsze zmiany w DOM, które będą nadal przerywane przez twoje wywołanie zwrotne.

Co więcej, dlatego, że wydarzenia propagują się w taki sam sposób, jak w przypadku normalnych wydarzeń w DOM, zaczniesz słyszeć zmiany na elementach, których możesz nie obchodzić lub nie uwzględniać w kodzie. Tak więc cały mechanizm zdarzeń mutacji DOM może stać się kłopotliwy w zarządzaniu dość szybko.

Obserwatorzy mutacji DOM przeciwdziałają tym problemom, ponieważ nazwa sugeruje obserwację zmian w DOM i dostarczenie raportu o wszystkich zmianach, które miały miejsce od początku zmiany. Jest to o wiele lepsza sytuacja, ponieważ umożliwia przeglądarkom powiadamianie użytkownika w czasie, który ma sens, na przykład, gdy dokument jest bezczynny i wszystkie inne skrypty JavaScript, które mogą spowodować, że dalsze zmiany zostały zakończone, lub zanim przeglądarka uruchomi ponownie cykl recalc/repaint, dzięki czemu można zastosować dowolne zmiany, bez konieczności powtarzania cyklu krótko po.

Ułatwia również zarządzanie, ponieważ można skanować wszystkie zmienione elementy, aby znaleźć to, czego szukasz, zamiast pisać wiele kodów obsługi spraw dotyczących rzeczy, których nie obchodzi, ponieważ była sytuacja z Mutation Events. A co ważniejsze, tylko jeden raz to nazwie, więc nie musisz się martwić, że jakiekolwiek dalsze zmiany będą wpływać na elementy, tj. Nie są już w zmiennym stanie, zmieniły się.

W odpowiedzi na twoje pytanie, Obserwatorzy mutacji DOM są wolniejsi, ponieważ czekali, aż jQuery zakończy manipulację DOM, zanim powiadomi Cię o zmianie jQuery. Które z powodów wyjaśnionych powyżej i twojego przykładu, udowadnia, że ​​jest bezpieczniejsze, bardziej wydajne rozwiązanie (nie powodujesz już błędu) i nie obchodziło cię, że jQuery dodało coś do DOM, ponieważ usunąłoby to wkrótce. W przypadku obserwatorów otrzymasz raport z informacją, że element jQuery został dodany i usunięty.

To nadal jest trochę kłopotliwe, ponieważ musisz dowiedzieć się, co właściwie się stało, dopasowując elementy do wszystkich zmian, które miały miejsce. W rzeczywistości nic nie zaszło (ten sam element został dodany i usunięty), więc nic się nie zmieniło w strukturze DOM. Aby pomóc z tym jest trochę biblioteka nazywa MutationSummary:

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

który oblicza efekt netto zmian i tylko nazywa swoją zwrotnego przechodząc w tych zmianach. Więc w twoim przypadku twój callback nie zostałby w ogóle wywołany, ponieważ efekt netto zmiany był zerowy.

E.g. dla następnych otrzymasz tylko jedną zmianę. Styl ciała został zmieniony na lewy: 1000px. Mimo że zmieniłem go w 1000 krokach. Efektem netto zmiany jest tylko różnica między jej wartością początkową a jej ostatnią.

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

Wielkie dzięki @AshHeskes i miłe wyjaśnienie! W końcu rozumiem ich zasady wykonywania. –

6

Prostą odpowiedzią jest to, że obserwatorzy mutacji są asynchroniczni. Są wysyłane za każdym razem, gdy silnik odczuwa podobny efekt, jakiś czas po zmianie, a w niektórych przypadkach po dokonaniu wielu zmian. Może to potrwać długo po tym, jak detektor zdarzeń mutacji DOM powiadomiłby Cię, ale w międzyczasie silnik mógł wykonywać swoją pracę bez konieczności ciągłego tworzenia zdarzeń i bańki dla każdej zmiany DOM.

+0

Dzięki Nartowicz! –

Powiązane problemy