Выполнение цикла по элементам и добавление к нему обработчиков снижает производительность

#javascript #jquery #performance #jquery-events

#javascript #jquery #Производительность #jquery-события

Вопрос:

Влияет ли производительность, когда я перебираю элементы списка и добавляю обработчик кликов ко всем отдельным элементам?

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

Код, который я сейчас использую, это:

 $('ul.paginator li').each(function() {
  if ($('a', this).length > 0) {
    $(this).css('cursor', 'pointer');
    $(this).click(function() {
      location.href = $('a', this).attr('href');
    });
  }
});
  

Ответ №1:

Я не уверен, насколько это может повлиять на производительность, но рассматривали ли вы возможность использования несколько упрощенного селектора jQuery:

 $('ul.paginator li:has(a)').each(
    function(){
        $(this).css('cursor','pointer').click(
            function(){
                location.href = $(this).find('a').attr('href');
            });
    });
  

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


Отредактировано для снижения затрат на has() :

 $('ul.paginator li a').each(
    function(){
        var address = this.href;
        $(this).closest('li').css('cursor','pointer').click(
            function(){
                location.href = address;
            });
    });
  

Это должно быть дешевле, так как оно будет выбирать только те a элементы внутри li , а затем перемещаться вверх, чтобы повлиять на этот li элемент.

Комментарии:

1. :has(a) является дорогостоящим с точки зрения вычислений

2. @David Thomas: отлично! не думал об has() этом! Именно то, что я искал. Я даже больше не использую each() . Теперь я могу просто сделать: $('ul.paginator li:has(a)').click(function() {}).css();

3. @Raynos: owh: ( Насколько это плохо?

4. @Raynos, это так; но больше, чем выполнение if инструкции для каждого элемента, возвращаемого селектором?

5. @DavidThomas да, это так. лучше сделать это вручную, чем в селекторе, если только это не правильный селектор, а не поддельный jquery

Ответ №2:

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

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

Ответ №3:

Да, лучше использовать delegate с правильным селектором, который выбирает только нужные вам элементы.

Будет создан и подключен только один обработчик.

Если вы не хотите использовать has() , этого будет достаточно (нет необходимости в нескольких обработчиках):

 $('ul.paginator').delegate('click', 'li', function() {
    var link = $('a', this);
    if (link.length > 0) {
        location.href = link.attr('href');
    }
});
  

Комментарии:

1. Но дело в том, что для этого нет подходящего селектора. Поправьте меня, если я ошибаюсь.

2. Обновлен ответ, если вы не хотите использовать has

3. Я бы добавил класс css (т. Е. ‘интерактивно’) для каждого li из них по a мере их рендеринга (это решило бы многие проблемы). При текущем подходе я бы сделал $('ul.paginator').find('a').closest('li').css('cursor', 'pointer')