2012-03-14 20 views
17

teraz większość ludzi na tej stronie są prawdopodobnie świadomi, że:Dlaczego nie skorzystać z delegowania zdarzeń JavaScript do ekstremum?

$("#someTable TD.foo").click(function(){ 
    $(e.target).doSomething(); 
}); 

zamierza wykonać znacznie gorsze niż:

$("#someTable").click(function(){ 
    if (!$(e.target).is("TD.foo")) return; 
    $(e.target).doSomething(); 
}); 

Teraz ile gorzej będzie oczywiście zależeć od tego, ile TDS stole ma, ale ta ogólna zasada powinna obowiązywać, o ile masz co najmniej kilka niszczycieli czołgów. (UWAGA: Oczywiście mądrą rzeczą byłoby użycie delegata jQuery zamiast powyższego, ale ja po prostu próbowałem zrobić przykład z oczywistym zróżnicowaniem).

W każdym razie wyjaśniłem tę zasadę współpracownikowi, a ich odpowiedź brzmiała: "Cóż, w przypadku składników obejmujących całą witrynę (np. INPUT wybierających datę), dlaczego warto tam zatrzymać? Dlaczego nie po prostu połączyć jednego handlera dla każdego typu? elementu do samego CIAŁA? " Nie miałem dobrej odpowiedzi.

Oczywiście użycie strategii delegacji oznacza ponowne przemyślenie sposobu blokowania zdarzeń, więc to jedna z wad. Ponadto hipotetycznie mogłaby mieć stronę, na której masz "TD.foo", że nie powinien mieć zajęte zdarzenia do niego. Ale jeśli zrozumiesz i będziesz skłonny pracować nad wydarzeniem, które się zmienia, i jeśli wymuszasz politykę: "jeśli umieścisz .foo na TD, ZAWSZE zacznie się to wydarzenie", żadne z nich nie wydaje się być Wielka rzecz.

Czuję, że muszę czegoś przeoczyć, więc moje pytanie brzmi: czy istnieje jakaś inna wada polegająca na delegowaniu wszystkich zdarzeń dla wszystkich elementów składowych całej witryny do BODY (w przeciwieństwie do wiązania ich bezpośrednio z elementami HTML) lub delegowanie ich do elementu macierzystego innego niż BODY)?

+0

wierzę, że jest to kwestia preferencji i scenariusz po wypadku . Mam na myśli to, że powinieneś najpierw napisać kod, aby był możliwie jak najbardziej czytelny. W ten sposób Ty lub ktoś inny może przyjść i zbadać kod później i mieć łatwy czas z nim. Gdy to zrobisz, możesz sprawdzić, czy kod działa dobrze i zoptymalizować go w razie potrzeby. W twoim konkretnym scenariuszu $ ("someTable TD.foo") jest łatwiejsze do odczytania, zarządzania i śledzenia niż scenariusz ze zwrotem w nim. Ktoś może przeczytać drugi kod i zinterpretować go, powodując, że wprowadzają błędy wraz ze zmianami. Tylko moja opinia: – evasilchenko

+0

Jestem w całkowitej i całkowitej zgodzie: programiści powinni zaprojektować najpierw, nie martwiąc się o optymalizację, i tylko później optymalizować odpowiednio. Jednak cała ta sprawa wyszła z rzeczywistej potrzeby zoptymalizowania istniejącego projektu (mieliśmy świetną stronę, dopóki nasi klienci nie zdecydowali się jej użyć w tysiącach wierszy), więc staraliśmy się wymyślić najlepszą strategię aby obsłużyć tę optymalizację. – machineghost

+1

możliwy duplikat [Czy wszystkie zdarzenia jquery powinny być powiązane z $ (dokument)?] (Http://stackoverflow.com/q/12824549/1048572) – Bergi

Odpowiedz

20

To, czego brakuje, to różne elementy wydajności.

Twój pierwszy przykład działa gorzej podczas ustawiania obsługi kliknięcia, ale działa lepiej, gdy zostanie wywołane faktyczne zdarzenie.

Twój drugi przykład działa lepiej podczas konfigurowania obsługi kliknięcia, ale działa znacznie gorzej, gdy zostanie wywołane faktyczne zdarzenie.

Jeśli wszystkie zdarzenia zostały umieszczone na obiekcie najwyższego poziomu (np. Dokumencie), to masz ogromną listę selektorów do sprawdzania każdego zdarzenia, aby znaleźć funkcję obsługi, z którą się łączy. Właśnie z tego powodu jQuery wycofał metodę .live(), ponieważ wyszukuje wszystkie zdarzenia w obiekcie dokumentu i kiedy było dużo rejestratorów zdarzeń .live() zarejestrowanych, wydajność każdego zdarzenia była zła, ponieważ musiała porównywać każde zdarzenie do partii i partii selektorów znaleźć odpowiednią procedurę obsługi zdarzeń dla tego wydarzenia. W przypadku pracy na dużą skalę, znacznie skuteczniejsze jest wiązanie zdarzenia tak blisko rzeczywistego obiektu, który wywołał zdarzenie. Jeśli obiekt nie jest dynamiczny, należy powiązać zdarzenie z obiektem, który go wyzwoli. Może to kosztować trochę więcej procesora po pierwszym powiązaniu zdarzenia, ale faktyczne wyzwalanie zdarzenia będzie szybkie i będzie skalowane.

jQuery's .on() i .delegate() mogą być użyte do tego, ale zaleca się, aby znaleźć obiekt przodka, który jest jak najbardziej zbliżony do obiektu wyzwalającego. Zapobiega to gromadzeniu się wielu dynamicznych zdarzeń na jednym obiekcie najwyższego poziomu i zapobiega obniżeniu wydajności podczas obsługi zdarzeń.

W przykładzie powyżej, jest to całkowicie uzasadnione zrobić:

$("#someTable").on('click', "td.foo", function(e) { 
    $(e.target).doSomething(); 
}); 

To dałoby ci jedną zwartą reprezentację obsługi click dla wszystkich wierszy i będzie nadal działać, nawet jak dodane/usunięte wiersze.

Ale to nie miałoby sensu, jak:

$(document).on('click', "#someTable td.foo", function(e) { 
    $(e.target).doSomething(); 
}); 

bo to byłoby mieszanie wydarzenia tabeli w przypadku wszystkich innych wydarzeń najwyższym poziomie w strony, gdy nie ma rzeczywistej potrzeby, aby to zrobić. Pytasz tylko o problemy z wydajnością w obsłudze zdarzeń bez żadnej korzyści z obsługi zdarzeń tam.

Myślę więc, że krótka odpowiedź na twoje pytanie jest taka, że ​​obsługa wszystkich zdarzeń w jednym miejscu na najwyższym poziomie prowadzi do problemów z wydajnością, gdy zdarzenie jest uruchamiane, ponieważ kod musi określać, który przewodnik powinien otrzymać wydarzenie, gdy jest wiele wydarzeń odbywa się w tym samym miejscu. Obsługa zdarzeń tak blisko obiektu generującego, jak to jest praktyczne, sprawia, że ​​obsługa zdarzeń jest bardziej wydajna.

+1

Dziękuję za to szczegółowe wyjaśnienie. W przypadku, w którym patrzyliśmy (tabela z dziesiątkami tysięcy TD) wydajność łączenia zdarzeń była wąskim gardłem, ale twoje wyjaśnienie pomogło mi zrozumieć, że w wielu innych istotnych przypadkach na naszej stronie wydajność rozwiązywania zdarzeń będzie miała większe znaczenie niż zdarzenie wydajność podłączania (i zbyt duże wiązanie z dokumentem negatywnie wpłynęłoby na wydajność rozdzielczości). Więc ... teraz nie będziemy globalnie wiążący wszystkiego :-) – machineghost

3

Jeśli robiłeś to w prostym kodzie JavaScript, wpływ losowych kliknięć w dowolne miejsce na zdarzenia wyzwalające stronę jest prawie zerowy. Jednak w jQuery konsekwencja może być znacznie większa ze względu na ilość surowych poleceń JS, które musi uruchomić, aby uzyskać ten sam efekt.

Osobiście uważam, że mała delegacja jest dobra, ale zbyt duża jej część spowoduje więcej problemów niż rozwiązuje.

3
  • Po usunięciu węzła odpowiednie detektory nie są automatycznie usuwane.
  • Niektóre zdarzenia po prostu nie bańkę
  • różnych bibliotek może złamać system przez zatrzymywanie propagacji zdarzenia (domyślam się, że wspomnieć, że jeden)
Powiązane problemy