$ .each () проти for () цикл - і продуктивність


75

Це, в основному, лише деякі речі, про які я дивувався, можливо, хтось може дати мені трохи більше уявлення про них, я також поділюся тим, що я помітив до цього часу!

Перше, що мені було цікаво ... чи є якась різниця корисна чи причина використовувати:

$('element').each(function (i, el) { });

-- проти --

$.each($('element'), function (i, el) { });

Переглядаючи документи jQuery, я не бачу жодної рими чи причини того чи іншого (можливо, ви знаєте приклад або додаткові дії, які можна зробити над іншими.

Але що ще важливіше, мене тут хвилює швидкість

// As opposed to $.each() looping through a jQuery object
// -- 8x faster 
for (var i = 0, $('.whatever').length; i < len; i++) {
    $('.whatever')[i] // do stuff
}

Якщо ви заглянете цю jsFiddle DEMO тут , ви побачите, що різниця в швидкості в основному еквівалентна будь-якій з них, але, що важливіше, я відчуваю, що завжди повинен використовувати for()цикли ...

Я просто перевіряв модуль (перебираючи кожну з 5 різних функцій сценарію, 50 000 разів), просто переглядаючи купу елементів списку, і встановлюючи data-newAttr, нічого особливого.


ЗАПИТАННЯ: Думаю, моє найбільше питання полягає в тому, чому не завжди використовувати для циклів під час ітерації через об'єкт ?? Чи є сенс використовувати $ .each ()? Чи завжди ви використовуєте цикли for (), навіть коли переглядаєте об'єкти jQuery?

jsFiddle DEMO тут

Function type:                  Execution Time:
_testArea.each() + $(this)               1947   <-- using $(this) slows it down tremendously
$.each()         + $(this)               1940
_testArea.each() + el(plain JS)           458   <-- using the Element speeds things up
$.each()         + el(plain JS)           452
for() loop       + plainJS[0] iteration   236   <-- over 8x faster

Тільки мої 2 центи. :)


31
Як колись Джо Армстронг писав у відповідь на подібне запитання в списку розсилки Ерланга, "Просто напишіть найкрасивішу програму, яку зможете". Нехай проблеми з продуктивністю приходять до вас. Ви справді будете працювати на сторінках, які повторюються 50 000 разів? Якщо так, то неодмінно оптимізуйте.
Пойнті

3
Як може forвиглядати ітерація циклу над елементами DOM jQuery?
Йорданія

2
Перевірте це самі на jsperf.com
j08691

1
Завжди функції Javascript будуть швидшими, ніж функції Jquery, оскільки javascript є рідним, але я думаю, що сенс використання кожного замість for, це зробити код швидшим, використовуючи фреймворк, і переваги
Хорхе

5
.each()Метод перебирає об'єкти JQuery. $.each()Статичний метод може перебирати різні типи об'єктів, як і звичайні об'єкти, масиви і масив подібних об'єктів. У цьому різниця.
Šime Vidas

Відповіді:


47

Одна річ, яка .each()дозволяє робити те, що неможливо зробити за допомогою forциклу, - це ланцюжок .

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

Я погрався з вашим JSFiddle, щоб побачити, як ланцюжок впливатиме на продуктивність у випадках, коли вам доведеться перебирати підмножини вихідного набору відповідних елементів.

Результат виявився не таким несподіваним, хоча я думаю, що накладні витрати end()тут були перебільшені через поєднання кількох елементів та багатьох циклів. Окрім цього: прості цикли JS все ще трохи швидші, але чи важить це до додаткової читабельності .each()(та ланцюжка), це спірне питання.


Оце Так! Дякую, навіть не замислювався про таке ланцюжку, це, безумовно, сама велика користь! Це набагато більше коду, щоб зробити в простому JS, і як тільки у вас є купу, якщо / інакше, що відбувається для того, щоб виконати те саме, вигода від MS практично не існує.
Mark Pieszak - Trilon.io

1
неформант! Я фільтрував би всередині зовнішнього кожного () лише тому, що кожен (). Filter () обробляв би один і той же масив двічі, він менш зручний, але більш продуктивний. І якщо ви очікуєте великої кількості елементів, тоді я б взагалі утримався від використання кожної () ітерації, просто погляньте на jsperf.com/function-call-overhead-test щодо накладних викликів функції
comeGetSome

22

Одне, що ви отримуєте, .each()- це автоматичне локальне масштабування (оскільки ви викликаєте анонімну функцію для кожного об’єкта), що, у свою чергу, означає, що якщо ви створюєте ще більше анонімних функцій / закриттів / обробників подій / незалежно від кожної ітерації, вам ніколи не доведеться турбуйтеся про те, що ваші обробники діляться змінною. Тобто, JavaScript не діє як інші мови, коли справа стосується локальних областей застосування, але оскільки ви можете декларувати змінну де завгодно, це іноді може вас обдурити.

Іншими словами, це неправильно:

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

Всякий раз, коли будь-який із цих об'єктів викликає свій "someEvent" після цього циклу (будь ласка, зауважте, що це вигадано), попередження завжди буде говорити про те, що було призначено останньому idx, що повинно бути (станом на час, що викликається) someObjectArray.length;

Щоб переконатися, що ви зберегли належний індекс, вам потрібно оголосити локальну область, створити змінну та призначити цій змінній для використання.

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

Як бачите, це потворно, як пекло, але це має спрацювати. Кожен обробник подій отримує власну копіюlocalidx

А тепер порівняйте це з .each()

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

Набагато простіше, чи не так?


1
Дуже правильно! Я насправді на секунду забув, що це вже робить для вас ... Думаю, найбільше, що можна взяти з усього, - це те, що якщо ви хочете простої маніпуляції | get / set типу речей, простий для () звичайний JS - це справді шлях. Для набагато складніших фільтрів та обробників подій вам майже потрібен кожен (). Цікаво ...
Марк Пішак - Trilon.io

9

jQuery.each проти for-loop

Переваги jQuery.each:

  • Добре вписується в код jQuery (ланцюжок та стиль).
  • Не турбуйтеся про область (посилання на ітератор та об'єкт будуть постійними).
  • Може використовуватися універсально (для всіх типів об’єктів та ітерації за клавішами об’єктів).

Переваги для циклу:

  • Висока продуктивність (для ігор / анімації / великих наборів даних).
  • Повний контроль над ітератором (пропускати елементи, зрощувати елементи зі списку тощо).
  • Цикл for завжди буде працювати, оскільки немає залежності від jQuery.
  • Той самий знайомий синтаксис, що і більшість інших подібних мов.

Приклад коду

Це приклад коду того, як я вважаю за краще перебирати список.

var list = ['a', 'b', 'c', 'd', 'e', 'f'];

jQuery.each:

$.each(list, function(i, v)
{
    // code...
});

For-loop без закриття:

for(var i=0,v,n=list.length;i<n;i+=1)
{
    v = list[i];
    // code...
}

For-loop із закриттям:

for(var i=0,n=list.length;i<n;i+=1)
{
    (function(i, v)
    {
        // code...
    })(i, list[i]);
}

Примітка: Я пропоную вам просто використовувати стандартний for-loop і використовувати замикання лише тоді, коли це необхідно. Однак коли ваш код і так схожий на jQuery, ніж на Javascript, його може бути простіше просто використовувати $.each. У разі проблем із продуктивністю, ви завжди можете розглянути це пізніше.


5

Я провів кілька простих тестів продуктивності, коли раніше http://jsperf.com/forloops3 . Здається, дотримуватися простого, старого for loop(де це можливо) - це шлях :)


4

Коли я зайшов за вашим посиланням, ось два цифри, які я отримав:

$.each() + el(plain JS) 401
for() loop + plainJS[0] iteration   377

Якщо різниця така мала, тоді використовуйте той, який є найбільш читабельним, але, якщо у вас дуже високі вимоги до часу, то вам може знадобитися просто піти з тим, що в кінцевому підсумку стане найшвидшим.

Я б запропонував вам написати вашу програму, використовуючи три різні методи, два вищезазначені, а потім використовувати foreach, знайдений у нових версіях javascript, а для тих браузерів, які цього не підтримують, ви можете додати його як прототип.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

Ви знаєте, які ваші вимоги і що робитиме ваша програма, тому просто напишіть власні тести та переконайтеся, що вони відповідають вимогам у браузерах, які ви будете підтримувати.

На ваше перше запитання я б погодився, $('element').eachоскільки його набагато легше читати, але це лише моя думка.


2
Хоча для таких невеликих полів це, швидше за все , не робить різниці [римується зі спамом] .. Я б просто використав "більш чітку послідовну версію" (залежно від того, яка з них визначена), якщо не було конкретної реальної діяльності випадок, який вказує, що він був занадто повільним.

1
@pst - Невеликий запас може змінити ситуацію, якщо ви зателефонуєте йому 10000 разів, і ця невелика різниця виведе вас за межі дозволеного вікна, про що я просив, і єдиний спосіб справді знати - це тестування в різних браузерах за допомогою три версії і отримати деякі цифри.
James Black

Дякую Джеймсе! Так, у моєму випадку це однозначно проблема, нам потрібно підтримувати застарілі браузери, але тепер я бачу, що читабельність та зручність використання - розумно - це має сенс використовувати each(), а згодом дотримуватися прямого простого JS! Різниця насправді не існує, здається, що якщо мені це не потрібно, щоб залишитися об'єктом JS, мені не потрібно використовувати $(this).
Mark Pieszak - Trilon.io

2

Насправді існує велика різниця між $ .each () та $ (). Each ().

Вони роблять дещо різні речі залежно від того, що ви передаєте.

http://api.jquery.com/each/ проти http://api.jquery.com/jquery.each/

jquery.each - загальний ітератор, де $ (). кожен () є специфічним для колекції jquery.

Див. Також: http://jsperf.com/each-vs-each-vs-for-in/9


Ви можете так само легко використовувати обидва однакові способи: $(['someItem', 'anotherItem']).each(function (i, el) { }); jsfiddle.net/zzVQD . Також це не означає, що питання заслуговує на голосування, я вклав у нього багато досліджень / коду / зусиль.
Mark Pieszak - Trilon.io

1
хоча це не відповідь на це питання, воно додає певні знання.
своп
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.