Почему бы не переместить Javascript в крайность?

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

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

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

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

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

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

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

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

Ответ 1

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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