Почему бы не довести делегирование событий Javascript до крайности? - PullRequest
18 голосов
/ 15 марта 2012

К настоящему времени большинство людей на этом сайте, вероятно, знают, что:

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

будет работать намного хуже, чем:

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

Теперь, насколько хуже, конечно, будет зависеть отсколько TD у вашей таблицы, но этот общий принцип должен применяться, если у вас есть хотя бы несколько TD.(ПРИМЕЧАНИЕ. Конечно, разумно было бы использовать делегат jQuery вместо вышеупомянутого, но я просто пытался сделать пример с очевидным различием).

Во всяком случае, я объяснил этот принцип совместнорабочий, и их ответ был «Ну, для компонентов всего сайта (например, INPUT выбора даты) зачем останавливаться на этом? Почему бы просто не привязать один обработчик для каждого типа компонента к самому BODY?»У меня не было хорошего ответа.

Очевидно, что использование стратегии делегирования означает переосмысление того, как вы блокируете события, так что это один недостаток.Кроме того, гипотетически у вас может быть страница, где у вас есть «TD.foo», для которого не должен иметь событие, подключенное к нему.Но, если вы понимаете и хотите обойти всплывающее изменение события, и если вы применяете политику «если вы помещаете .foo в TD, это ВСЕГДА собирается подключить событие», ни один из них не выглядит какбольшое дело.

Я чувствую, что, должно быть, чего-то не хватает, поэтому мой вопрос: есть ли другой недостаток, если просто делегировать все события для всех компонентов всего сайта в BODY (в отличие от непосредственного их связывания)?элементам HTML или делегированию их родительскому элементу, отличному от BODY)?

Ответы [ 3 ]

22 голосов
/ 15 марта 2012

Что вам не хватает, так это различные элементы производительности.

Ваш первый пример работает хуже при настройке обработчика щелчков, но работает лучше, когда запускается фактическое событие.

Ваш второй пример работает лучше при настройке обработчика щелчков, но значительно хуже при срабатывании фактического события.

Если все события были помещены в объект верхнего уровня (например, в документ), то вы быиметь огромный список селекторов для проверки каждого события, чтобы определить, с какой функцией-обработчиком оно связано.Именно из-за этого jQuery устарел метод .live(), потому что он ищет все события в объекте документа, и когда было зарегистрировано много обработчиков событий .live(), производительность каждого события была плохой, потому что пришлось сравнивать каждое событие с партиями.и множество селекторов, чтобы найти соответствующий обработчик события для этого события.Для крупномасштабной работы гораздо, гораздо эффективнее привязать событие как можно ближе к реальному объекту, который вызвал событие.Если объект не является динамическим, то свяжите событие прямо с объектом, который его инициирует.Когда вы впервые связываете событие, это может стоить чуть больше ЦП, но фактический запуск события будет быстрым и будет масштабироваться.

.on() и .delegate() в jQuery могут использоваться для этого, но этоРекомендуется найти объект-предок как можно ближе к вызывающему объекту.Это предотвращает накопление большого количества динамических событий на одном объекте верхнего уровня и предотвращает снижение производительности при обработке событий.

В приведенном выше примере вполне разумно сделать:

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

даст вам одно компактное представление обработчика щелчков для всех строк, и он будет продолжать работать даже после добавления / удаления строк.

Но это не имеет особого смысла:

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

потому что это будет смешивать события таблицы со всеми другими событиями верхнего уровня на странице, когда в этом нет особой необходимости.Вы запрашиваете только проблемы с производительностью при обработке событий, но не получаете никакой выгоды от обработки событий там.

Итак, я думаю, что краткий ответ на ваш вопрос заключается в том, что обработка всех событий в одном месте верхнего уровня приводит к проблемам с производительностью.когда событие инициируется, так как код должен определить, какой обработчик должен получить событие, когда в одном и том же месте обрабатывается много событий.Обработка событий настолько близко к генерирующему объекту, насколько это практически возможно, делает обработку событий более эффективной.

3 голосов
/ 15 марта 2012
  • Если вы удалите узел, соответствующие слушатели не будут удалены автоматически.
  • Некоторые события просто не всплывают
  • Различные библиотеки могут нарушить работу системы, остановив распространение события (думаю, вы упомянули это)
3 голосов
/ 15 марта 2012

Если вы делали это в простом JavaScript, влияние случайных нажатий в любом месте на странице, вызывающей события, практически равно нулю. Однако в jQuery последствия могут быть намного более значительными из-за количества необработанных команд JS, которые он должен выполнить для получения того же эффекта.

Лично я считаю, что небольшая делегация хороша, но слишком большая ее часть вызовет больше проблем, чем решит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...