Skąd to pochodzi
Kiedy po raz pierwszy nauczyłem się jQuery, zwykle dołączałem takie zdarzenia:
$('.my-widget a').click(function() {
$(this).toggleClass('active');
});
Gdy dowiedziałem się więcej o szybkości selektora i delegowaniu zdarzeń, przeczytałem w kilku miejscach, że „delegowanie zdarzeń jQuery przyspieszy Twój kod”. Zacząłem więc pisać taki kod:
$('.my-widget').on('click','a',function() {
$(this).toggleClass('active');
});
Był to również zalecany sposób replikacji zachowania przestarzałego zdarzenia .live (). Co jest dla mnie ważne, ponieważ wiele moich witryn przez cały czas dynamicznie dodaje / usuwa widżety. Powyższe nie zachowuje się jednak dokładnie tak, jak .live (), ponieważ tylko elementy dodane do już istniejącego kontenera „.my-widget” otrzymają takie zachowanie. Jeśli dynamicznie dodam kolejny blok html po uruchomieniu tego kodu, elementy te nie otrzymają powiązanych z nimi zdarzeń. Lubię to:
setTimeout(function() {
$('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);
Co chcę osiągnąć:
- stare zachowanie .live () // oznaczające przypisywanie zdarzeń do jeszcze nieistniejących elementów
- zalety .on ()
- najszybsza wydajność do wiązania zdarzeń
- Prosty sposób na zarządzanie wydarzeniami
Dołączam teraz wszystkie zdarzenia takie jak to:
$(document).on('click.my-widget-namespace', '.my-widget a', function() {
$(this).toggleClass('active');
});
Co wydaje się spełniać wszystkie moje cele. (Tak, z jakiegoś powodu jest wolniejsze w IE, nie mam pojęcia dlaczego?) Jest szybkie, ponieważ tylko jedno zdarzenie jest powiązane z pojedynczym elementem, a selektor pomocniczy jest oceniany tylko wtedy, gdy zdarzenie się wydarzy (proszę poprawić mnie, jeśli jest źle). Przestrzeń nazw jest niesamowita, ponieważ ułatwia przełączanie nasłuchiwania zdarzeń.
Moje rozwiązanie / pytanie
Zaczynam więc myśleć, że zdarzenia jQuery powinny być zawsze powiązane z $ (dokument).
Czy jest jakiś powód, dla którego nie chcesz tego robić?
Czy można to uznać za najlepszą praktykę? Jeśli nie, dlaczego?
Jeśli przeczytałeś to wszystko, dziękuję. Doceniam wszelkie / wszystkie opinie / spostrzeżenia.
Założenia:
- Korzystanie z jQuery obsługującego
.on()
// co najmniej wersję 1.7 - Chcesz, aby wydarzenie zostało dodane do dynamicznie dodawanej zawartości
Odczyty / Przykłady:
źródło
Odpowiedzi:
Nie - NIE należy wiązać wszystkich delegowanych programów obsługi zdarzeń z
document
obiektem. To prawdopodobnie najgorszy scenariusz, jaki można stworzyć.Po pierwsze, delegowanie zdarzeń nie zawsze przyspiesza kod. W niektórych przypadkach jest to korzystne, aw niektórych nie. Z delegowania zdarzeń należy korzystać, gdy faktycznie jest potrzebne delegowanie zdarzeń i gdy jest to korzystne. W przeciwnym razie należy powiązać programy obsługi zdarzeń bezpośrednio z obiektami, w których ma miejsce zdarzenie, ponieważ zazwyczaj będzie to bardziej wydajne.
Po drugie, NIE powinieneś wiązać wszystkich delegowanych wydarzeń na poziomie dokumentu. Właśnie z tego
.live()
powodu został uznany za przestarzały, ponieważ jest to bardzo nieefektywne, gdy w ten sposób jest powiązanych wiele wydarzeń. W przypadku obsługi zdarzeń delegowanych DUŻO bardziej efektywne jest powiązanie ich z najbliższym rodzicem, który nie jest dynamiczny.Po trzecie, nie wszystkie wydarzenia działają lub wszystkie problemy można rozwiązać za pomocą delegacji. Na przykład, jeśli chcesz przechwycić kluczowe zdarzenia w kontrolce wejściowej i zablokować wprowadzanie nieprawidłowych kluczy do kontrolki wejściowej, nie możesz tego zrobić za pomocą delegowanej obsługi zdarzeń, ponieważ do czasu, gdy zdarzenie przechodzi do delegowanej procedury obsługi, już ma zostały przetworzone przez kontrolkę wejściową i jest już za późno, aby wpłynąć na to zachowanie.
Oto sytuacje, w których delegowanie zdarzeń jest wymagane lub korzystne:
Aby lepiej to zrozumieć, należy zrozumieć, jak działają procedury obsługi zdarzeń delegowanych w jQuery. Kiedy zadzwonisz do czegoś takiego:
Instaluje na
#myParent
obiekcie ogólną procedurę obsługi zdarzeń jQuery . Gdy zdarzenie kliknięcia przechodzi do tej delegowanej procedury obsługi zdarzeń, jQuery musi przejść przez listę delegowanych programów obsługi zdarzeń dołączonych do tego obiektu i sprawdzić, czy element źródłowy zdarzenia pasuje do któregokolwiek z selektorów w delegowanych programach obsługi zdarzeń.Ponieważ selektory mogą być dość zaangażowane, oznacza to, że jQuery musi przeanalizować każdy selektor, a następnie porównać go z charakterystyką oryginalnego celu zdarzenia, aby sprawdzić, czy pasuje do każdego selektora. To nie jest tania operacja. Nie ma nic wielkiego, jeśli jest tylko jeden z nich, ale jeśli umieścisz wszystkie selektory w obiekcie dokumentu, a były setki selektorów do porównania z każdym pojedynczym zdarzeniem, może to poważnie pogorszyć wydajność obsługi zdarzeń.
Z tego powodu chcesz skonfigurować delegowane programy obsługi zdarzeń, aby delegowana procedura obsługi zdarzeń była jak najbliżej obiektu docelowego. Oznacza to, że mniej zdarzeń będzie przechodzić przez każdą delegowaną procedurę obsługi zdarzeń, poprawiając w ten sposób wydajność. Umieszczanie wszystkich delegowanych zdarzeń w obiekcie dokumentu to najgorsza możliwa wydajność, ponieważ wszystkie zdarzenia propagowane muszą przejść przez wszystkie delegowane programy obsługi zdarzeń i zostać ocenione względem wszystkich możliwych delegowanych selektorów zdarzeń. Właśnie dlatego
.live()
jest przestarzały, ponieważ tak właśnie.live()
było i okazał się bardzo nieefektywny.Aby więc osiągnąć optymalną wydajność:
źródło
$(document).on('click', '[myCustomAttr]', function () { ... });
?document
, czy też powiązać je z bardziej szczegółowymi zaznaczeniamipage:load
i rozłączyć te zdarzeniapage:after-remove
? HmmmDelegowanie zdarzeń to technika pisania programów obsługi, zanim element faktycznie zaistnieje w DOM. Ta metoda ma swoje wady i powinna być używana tylko wtedy, gdy masz takie wymagania.
Kiedy należy używać delegowania zdarzeń?
Dlaczego nie powinieneś używać delegowania zdarzeń?
PS: Nawet w przypadku zawartości dynamicznej nie musisz używać metody delegowania zdarzeń, jeśli łączysz procedurę obsługi po wstawieniu zawartości do DOM. (Jeśli zawartość dynamiczna nie jest dodawana często usuwana / ponownie dodawana)
źródło
Najwyraźniej delegowanie zdarzeń jest obecnie zalecane. przynajmniej dla vanilla js.
https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-vanilla-js/
„Występ w Internecie # Wydaje się, że słuchanie każdego kliknięcia w dokumencie byłoby niekorzystne dla wydajności, ale w rzeczywistości jest bardziej wydajne niż posiadanie grupy słuchaczy wydarzeń na poszczególnych elementach”
źródło
Chciałbym dodać kilka uwag i kontrargumentów do odpowiedzi jfriend00. (głównie moje opinie oparte na moich przeczuciach)
Chociaż prawdą jest, że wydajność może być nieco lepsza, jeśli zamierzasz zarejestrować i zdarzenie tylko dla jednego elementu, uważam, że nie jest to sprzeczne z korzyściami skalowalności, jakie przynosi delegowanie. Uważam również, że przeglądarki coraz wydajniej sobie z tym radzą, chociaż nie mam na to dowodów. Moim zdaniem delegacja na imprezy to droga!
W pewnym sensie się z tym zgadzam. Jeśli masz 100% pewności, że zdarzenie będzie miało miejsce tylko w kontenerze, sensowne jest powiązanie zdarzenia z tym kontenerem, ale nadal będę spierał się przeciwko powiązaniu zdarzeń bezpośrednio z elementem wyzwalającym.
To po prostu nieprawda. Zobacz ten kodPen: https://codepen.io/pwkip/pen/jObGmjq
Pokazuje, jak można zapobiec wpisywaniu przez użytkownika, rejestrując zdarzenie naciśnięcia klawisza w dokumencie.
Chciałbym odpowiedzieć tym cytatem z https://ehsangazar.com/optimizing-javascript-event-listeners-for-performance-e28406ad406c
Event delegation promotes binding as few DOM event handlers as possible, since each event handler requires memory. For example, let’s say that we have an HTML unordered list we want to bind event handlers to. Instead of binding a click event handler for each list item (which may be hundreds for all we know), we bind one click handler to the parent unordered list itself.
Ponadto
performance cost of event delegation google
wyszukiwanie w Google zwraca więcej wyników na korzyść delegowania wydarzeń.Gdzie to jest udokumentowane? Jeśli to prawda, to jQuery wydaje się obsługiwać delegowanie w bardzo nieefektywny sposób, a wtedy moje kontrargumenty powinny być stosowane tylko do waniliowego JS.
Mimo to: chciałbym znaleźć oficjalne źródło wspierające to twierdzenie.
:: EDYTOWAĆ ::
Wygląda na to, że jQuery rzeczywiście robi propagację zdarzeń w bardzo nieefektywny sposób (ponieważ obsługuje IE8) https://api.jquery.com/on/#event-performance
Tak więc większość moich argumentów odnosi się tylko do klasycznego JS i nowoczesnych przeglądarek.
źródło