Подтвердить что ты не робот

Делегирование событий против прямой привязки при добавлении сложных элементов на страницу

У меня есть такая разметка (классы только для объяснения):

<ol id="root" class="sortable">
  <li>
    <header class="show-after-collapse">Top-Line Info</header>
    <section class="hide-after-collapse">
      <ol class="sortable-connected">
        <li>
          <header class="show-after-collapse">Top-Line Info</header>
          <section class="hide-after-collapse">
            <div>Content A</div>
          </section>
        </li>
      </ol>
    </section>
  </li>
  <li>
    <header/>
    <section class="hide-after-collapse">
      <ol class="sortable-connected">
        <li>
          <header/>
          <section class="hide-after-collapse">
            <div>Content B</div>
          </section>
        </li>
      </ol>
    </section>
  </li>
</ol>

То есть, вложенные сортируемые списки. Однако сортируемый плагин достаточен, поскольку каждый li (далее "элемент" ) поддерживает свой уровень, хотя внутренние списки подключены. Элементы имеют всегда видимый заголовок и раздел, видимый, когда в расширенном состоянии, переключается нажатием на заголовок. Пользователь может добавлять и удалять элементы с любого уровня по желанию; добавление элемента верхнего уровня будет включать в себя пустой список гнезд внутри него. Мой вопрос заключается в инициализации JS вновь созданного элемента: хотя они будут совместно использовать некоторые общие функции, которые я могу покрыть с помощью

$("#root").on("click", "li > header", function() {
  $(this).parent().toggleClass("collapsed");
});

и

li.collapsed section {
  display: none;
}

(Боковой вопрос: было ли это подходящим местом для использования тегов/итоговых тегов HTML5? Кажется, что это похоже на то, будут ли они даже попадать в финальную спецификацию, и я хочу скользящий переход, так что кажется Мне все равно нужен JS, но я задаю вопрос массам. Привет, массы.)

Если корневой список является единственным (релевантным) элементом, который гарантированно существует при загрузке страницы, для эффективной работы .on() мне необходимо привязать все события к этому элементу и указать точное селектор для каждого, как я понимаю. Так, например, чтобы связать отдельные функции с двумя кнопками рядом друг с другом, я должен был бы каждый раз указывать селектор, & agrave; л

$("#root").on("change", "li > section button.b1", function() {
  b1Function();
}).on("change", "li > section button.b2", function() {
  b2Function();
});

Это точно? В этом случае имеет смысл отказаться от .on() и привязать мои события к моменту добавления нового элемента на страницу? Общее количество элементов, вероятно, будет насчитывать не больше десятков, если это имеет значение в ответе.

4b9b3361

Ответ 1

Вы создадите меньше накладных расходов процессора, связывая события с помощью $(<root-element>).on(<event>, <selector>), так как вы будете привязываться к одному "корневому" элементу, а не к потенциально более одиночным элементам-потомкам (каждая привязка требует времени...).

При этом вы будете получать больше накладных расходов ЦП, когда происходят реальные события, поскольку они должны пузырить DOM на "корневой" элемент.

Короткий рассказ: делегат сохраняет CPU при привязке обработчиков событий; bind сохраняет CPU при срабатывании событий (например, пользователь нажимает что-либо).

Итак, вам решать, какой момент важнее для производительности. У вас есть доступный CPU при добавлении новых элементов? Если это так, то привязка непосредственно к новым элементам будет наилучшей для общей производительности, однако, если добавление элементов - это интенсивная операция с процессором, вы, вероятно, захотите делегировать привязку события и позволить запуску события создать дополнительные избыточные ресурсы ЦП от всех пузырьков.

Обратите внимание, что:

$(<root-element>).on(<event>, <selector>, <event-handler>)

совпадает с:

$(<root-element>).delegate(<selector>, <event>, <event-handler>)

и что:

$(<selector>).on(<event>, <event-handler>)

совпадает с:

$(<selector>).bind(<event>, <event-handler>)

.on() является новым в jQuery 1.7, и если вы используете 1.7+, тогда .delegate(<selector>, <event>, <event-handler>) является просто сокращенным для .on(<event>, <selector>, <event-handler>).

UPDATE

Вот тест производительности, показывающий, что быстрее делегировать привязку события, чем привязывать к каждому элементу отдельно: http://jsperf.com/bind-vs-click/29. К сожалению, этот тест производительности удален.

UPDATE

Вот тест производительности, показывающий, что запуск события происходит быстрее, когда вы привязываетесь непосредственно к элементам, а не делегируете привязку: http://jsperf.com/jquery-delegate-vs-bind-triggering (Примечание что это не идеальный тест производительности, поскольку методы привязки включены в тест, но поскольку delegate работает быстрее при привязке, это означает, что bind еще быстрее относительно, говоря о запуске)

Ответ 2

Поскольку принятый ответ имеет неточные тесты (BTW: проверить свой код, измерить производительность, не просто слепо следовать некоторым "правилам" - это не то, как делается оптимизация!), а просто неправильно Я отправляю фиксированные тесты: https://jsperf.com/jquery-delegate-vs-bind-triggering/49

который доказывается на таком простом примере, нет никакой разницы между делегированием или прямой привязкой

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

Если у вас даже разница в 1 мс (не произойдет, но это всего лишь пример) на одно событие - как щелчок - вы этого не заметите. Если у вас есть разница 1 мс в событии, которое происходит 100 раз в секунду - вы заметите потребление ЦП.

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

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