Який найшвидший спосіб провести цикл через масив у JavaScript?


249

Я дізнався з книг, що слід писати для циклу, як це:

for(var i=0, len=arr.length; i < len; i++){
    // blah blah
}

тому arr.lengthзаряд не буде обчислюватися кожен раз.

Інші кажуть, що компілятор зробить певну оптимізацію цього, тому ви можете просто написати:

for(var i=0; i < arr.length; i++){
    // blah blah
}

Я просто хочу знати, який найкращий спосіб на практиці?


1
також варто звернути увагу на пошук циклу масивів: jsperf.com/array-loop-var-caching
cloakedninjas

@ wong2 Цей тест від Browserdiet має більш повну колекцію альтернатив.
Домі


Покращено на попередньому jsben: jsben.ch/#/R6LbS
Corbfon

Чи можемо ми представити for ... ofцикл цього змагання? Синтаксис здається ще простішим, ніж цикл для без кешування, і я хочу знати, чи слід переходити до використання циклів.
програмістРай

Відповіді:


339

Після виконання цього тесту у більшості сучасних браузерів ...

http://jsben.ch/dyM52

В даний час найшвидша форма циклу (і, на мою думку, найбільш синтаксично очевидна).

стандарт для циклу з кешуванням довжини

for (var i = 0, len = myArray.length; i < len; i++) {

}

Я б сказав, що це безумовно випадок, коли я аплодую розробникам двигуна JavaScript. Час виконання повинен бути оптимізований для ясності , а не кмітливості .


6
Цікаво, що в IE9 це швидше: для (var i = 0, len = myArray.length; i <len; ++ i) {} // префікс incr, а не постфікс
Christopher Bennage

4
Інші причини використання див. У розділі Переваги операторів префіксу над постфіксом++i .
Bennett McElwee

4
Я протестував за допомогою оператора префікса, як запропонував @BennettMcElwee, і він працює трохи швидше: for(var i=0, len=myArray.length; i<len; ++i) Перевірте jsperf.com/caching-array-length/84
victmo

21
Ви повинні бути обережними, використовуючи цю петлю. Я почав використовувати його і мені важко було відслідковувати помилку через одну помилку, яку я зробив. Якщо ви вкладете дві петлі так: jsfiddle.net/KQwmL/1 . Ви повинні бути обережними, щоб назвати var len по-різному в двох петлях, інакше друга петля замінить першу.
Руй Маркес

6
@WillshawMedia Ви можете оголосити кілька змінних одним varоператором. Як написано, lenнасправді визначається обсяг, як ви пропонуєте.
jondavidjohn

90

Абсолютний найшвидший спосіб пройти цикл через масив javascript:

var len = arr.length;
while (len--) {
    // blah blah
}

Дивіться http://blogs.oracle.com/greimer/entry/best_way_to_code_a для повного порівняння


1
Не забудьте використовувати var(інакше це lenстає глобальною змінною). Також див. Jsperf.com/loops для додаткових орієнтирів циклу.
Матіас Байненс

22
Повідомлення в блозі, на якому базується ця відповідь, зараз майже 4 роки, і багато що змінилося в js-двигунах за той час, дивіться мою відповідь нижче для оновленого порівняння.
jondavidjohn

1
Я згоден з @jondavidjohn. Я перевірив цей код і виявився менш ефективним ... Перевірте jsperf.com/caching-array-length/84
victmo

Наведена відповідь майже універсально (у веб-переглядачах) набагато повільніше, ніж у циклі for. Дивіться посилання JSPerf у прийнятій відповіді. Це велика ганьба, бо це надзвичайно читабельний ІМО.
Летаріон

3
Я здогадуюсь @jondavidjohn, що те, що ти маєш на увазі під "моєю відповіддю нижче" - це "моя відповідь вище", хаха.
Shanimal

40

Станом на червень 2016 року , роблячи кілька тестів на найновішій версії Chrome (71% ринку браузерів у травні 2016 року та більше):

  • Найшвидший цикл - це цикл for , як з довжиною кешування, так і без неї, що забезпечує дійсно подібну продуктивність. (Цикл for з кешованою довжиною іноді дає кращі результати, ніж той, без кешування, але різниця майже незначна, що означає, що двигун може бути вже оптимізований для вибору стандарту і, ймовірно, найпростішого для циклу без кешування).
  • Цикл while з зменшеннями був приблизно в 1,5 рази повільніше, ніж цикл for.
  • Цикл, що використовує функцію зворотного дзвінка (як стандартний дляEach), був приблизно в 10 разів повільніше, ніж цикл for.

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

  • Якщо ваш додаток повторює багато предметів, або ваш код циклу знаходиться у функції, яка часто використовується, відповідь є простою для циклу:

    for (var i = 0; i < arr.length; i++) {
      // Do stuff with arr[i] or i
    }
  • Якщо ваш додаток насправді не повторюється через багато елементів або вам просто потрібно робити невеликі ітерації тут і там, використовуючи стандартний зворотний виклик forEach або будь-яку подібну функцію з вибраної вами бібліотеки JS, може бути зрозуміліше і менш схильне до помилок, оскільки Область змінної індексу закрита, і вам не потрібно використовувати дужки, отримуючи доступ до значення масиву безпосередньо:

    arr.forEach(function(value, index) {
      // Do stuff with value or index
    });
  • Якщо вам дійсно потрібно подряпати кілька мілісекунд, ітерація на мільярди рядків і довжина масиву не змінюється протягом цього процесу, ви можете розглянути можливість кешування довжини у циклі. Хоча я вважаю, що це справді не потрібно:

    for (var i = 0, len = arr.length; i < len; i++) {
      // Do stuff with arr[i]
    }

Ні. jsbench.github.io/#67b13d4e78cdd0d7a7346410d5becf12 показує, що найшвидший - "Зворотний цикл, неявне порівняння, вбудований код" (105,221 ops / sec), а "Loop, кешоване значення, вбудований код" набрав лише 76 635 ops / sec (Chrome 38.0.2125.111 )
Fr0sT

@ Fr0sT Ваш орієнтир - це інший сценарій, який проходить масиви від індексу 1 до <= довжина. Звичайно, це призведе до різних результатів. Якщо ви спробуєте пройти масив на основі нуля з <length - що, як мені здається, це звичайний сценарій - ви виявите, що результати краще оптимізувати за допомогою звичайного циклу "for" (з кешованою довжиною трохи швидше).
CGodo

Kyopaxa змінив орієнтири на (0 <= i <довжина), результати однакові. "Зворотний цикл, неявне порівняння, функція виклику" набрав 365 коп / сек, тоді як "цикл, кешоване значення, вбудований код" набрав 350 коп / сек (FF 51)
Fr0sT

@ Fr0sT, якщо ви зміните кешовані на нуль основі керовані цикли без рівних порівнянь, наприклад for(let i=0, j=array.length; i < j; i++), вперед для циклів значно прискорюється. У кількох тестах, які я провів, він виграв, у більшості це було в межах помилки або зворотного циклу.
Ісаак Б

1
@IsaacB і все, вибачте, що я не помітив, що лавка є зовсім неправильною - всі прямі петлі повторюють 1..length, тоді як зворотні петлі ітератують довжину..0 (arr [length] елемент недійсний). Я виправив тести, і тепер вони показують такі результати: "Цикл, вбудований код" 360 616 ops / sec ± 0,27%, "Loop, кешоване значення, вбудований код" 345,786 ops / sec ± 2,18% (Sic!) "Зворотний цикл, неявне порівняння, вбудований код "322,640 ops / sec ± 2,90% (!!!). Випробування виконували FF51. Нова лава тут jsbench.github.io/#6bdfcd2692ba80c16a68c88554281570 . Тож здається, що не має сенсу уніфікувати петлі.
Fr0sT

31

Якщо замовлення не важливе, я віддаю перевагу такому стилю:

for(var i = array.length; i--; )

Він кешує довжину і набагато коротше писати. Але він буде повторюватися над масивом у зворотному порядку.


6
Ти щойно вбив.
Виньєш Раджа

вам не потрібно я> = 0 ;?
MarwaAhmad

3
@MarwaAhmad: Ні. i--Повертає число, і коли число є 0умовою, falseтому що Boolean(0) === false.
Фелікс Клінг

31

Це просто 2018 рік, тому оновлення може бути приємним ...

І я дійсно повинен не погодитися з прийнятою відповіддю . Він відкладається в різних браузерах. деякі роблять forEachшвидше, деякі for-loop, а деякі while тут є орієнтиром для всіх методів http://jsben.ch/mW36e

arr.forEach( a => {
  // ...
}

і оскільки ви можете бачити багато for-loop, як for(a = 0; ... )тоді, варто згадати, що без 'var' змінні будуть визначені глобально, і це може різко вплинути на швидкість, тому воно стане повільним.

Пристрій Даффа працює швидше в опері, але не в Firefox

var arr = arr = new Array(11111111).fill(255);
var benches =     
[ [ "empty", () => {
  for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
  for(var a = 0, l = arr.length; a < l; ++a)
    var b = arr[a] + 1;
}]
, ["for-loop++", () => {
  for(var a = 0, l = arr.length; a < l; a++)
    var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
  for(var a = 0; a < arr.length; ++a )
    var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
  for(var a = arr.length - 1; a >= 0; --a )
    var b = arr[a] + 1;
}]
,["while-loop", () => {
  var a = 0, l = arr.length;
  while( a < l ) {
    var b = arr[a] + 1;
    ++a;
  }
}]
, ["reverse-do-while-loop", () => {
  var a = arr.length - 1; // CAREFUL
  do {
    var b = arr[a] + 1;
  } while(a--);   
}]
, ["forEach", () => {
  arr.forEach( a => {
    var b = a + 1;
  });
}]
, ["for const..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( const a in ar ) {
    var b = a + 1;
  }
}]
, ["for let..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( let a in ar ) {
    var b = a + 1;
  }
}]
, ["for var..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( var a in ar ) {
    var b = a + 1;
  }
}]
, ["Duff's device", () => {
  var len = arr.length;
  var i, n = len % 8 - 1;

  if (n > 0) {
    do {
      var b = arr[len-n] + 1;
    } while (--n); // n must be greater than 0 here
  }
  n = (len * 0.125) ^ 0;
  if (n > 0) { 
    do {
      i = --n <<3;
      var b = arr[i] + 1;
      var c = arr[i+1] + 1;
      var d = arr[i+2] + 1;
      var e = arr[i+3] + 1;
      var f = arr[i+4] + 1;
      var g = arr[i+5] + 1;
      var h = arr[i+6] + 1;
      var k = arr[i+7] + 1;
    }
    while (n); // n must be greater than 0 here also
  }
}]];
function bench(title, f) {
  var t0 = performance.now();
  var res = f();
  return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
  // Here if you forget to put 'var' so variables'll be global
  for(a = 0, l = arr.length; a < l; ++a)
     var b = arr[a] + 1;
});
var times = benches.map( function(a) {
                      arr = new Array(11111111).fill(255);
                      return [a[0], bench(...a)]
                     }).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
  `<div>` +
    `<span>${title} &nbsp;</span>` +
    `<span style="width:${3+n/2}%">&nbsp;${Number(time.toFixed(3))}msec</span>` +
  `</div>`;

var strRes = times.map( t => template(...t) ).join("\n") + 
            `<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div {  clear:both   }
body > div > div > span {
  float:left;
  width:43%;
  margin:3px 0;
  text-align:right;
}
body > div > div > span:nth-child(2) {
  text-align:left;
  background:darkorange;
  animation:showup .37s .111s;
  -webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>


3
@Maykonn ви, мабуть, хотіли сказати, "і це працює скрізь, але Opera Mini"
дуб,

3
@Maykonn Який не вказаний у режимі перегляду за замовчуванням, оскільки у 0,18% всіх користувачів є IE8, і ви не повинні витрачати час на його підтримку; у 2018 році це мертвий кінь.
дуб

1
Це безумовно, якщо врахувати всіх користувачів у всьому світі. Але, на жаль, у певних частинах світу IE8 є актуальним ще.
Майконн

1
Якщо я можу, не лише різні веб-переглядачі матимуть різні результати за різних методів, але й ті самі браузери матимуть різні результати з різними введеннями. Величезний масив лише для числа буде дуже оптимізований, тоді як невеликий змішаний - не буде.
Каїдо

1
@Tahlil Дякую
nullqube

19

2014 Whileповернувся

Просто думаю логічно.

Подивись на це

for( var index = 0 , length = array.length ; index < length ; index++ ) {

 //do stuff

}
  1. Потрібно створити принаймні 2 змінні (індекс, довжина)
  2. Потрібно перевірити, чи індекс менший за довжину
  3. Потрібно збільшити індекс
  4. forцикл має 3 параметри

Тепер скажіть мені, чому це має бути швидше, ніж:

var length = array.length;

while( --length ) { //or length--

 //do stuff

}
  1. Одна змінна
  2. Жодних чеків
  3. індекс знижується (машини віддають перевагу тому)
  4. while має лише один параметр

Мене зовсім збентежило, коли Chrome 28 показав, що цикл for for швидше. Це, мабуть, має якесь бен

"Е, всі використовують цикл for, давайте зосередимося на цьому, розробляючи для хромування."

Але зараз, у 2014 році цикл while знову на хромі. це в 2 рази швидше, в інших / старших браузерах це було завжди швидше.

Нещодавно я зробив кілька нових тестів. Зараз у реальному світі цих коротких кодів нічого не вартує, і jsperf насправді не може виконати належним чином цикл while, тому що він повинен відтворити array.length, який також потребує часу.

ви не можете отримати фактичну швидкість циклу часу на jsperf.

вам потрібно створити власну власну функцію та позначити це window.performance.now()

І так ... певний шлях циклу просто не відбувається.

Справжньою проблемою є насправді маніпуляція куполом / час візуалізації / час малювання або як би ви хотіли це назвати.

Наприклад, у мене є сцена на полотні, де мені потрібно обчислити координати та зіткнення ... це робиться між 10-200 мікросекундами (не мілісекундами). насправді потрібні різні мілісекунди, щоб все вийшло. Так само, як і в DOM.

АЛЕ

Існує ще один надзвичайно ефективний спосіб використання loopу деяких випадках ... наприклад, для копіювання / клонування масиву

for(
 var i = array.length ;
 i > 0 ;
 arrayCopy[ --i ] = array[ i ] // doing stuff
);

Зверніть увагу на налаштування параметрів:

  1. Те саме, що в циклі while я використовую лише одну змінну
  2. Потрібно перевірити, чи не перевищує показник 0;
  3. Як ви бачите, цей підхід відрізняється від нормального для циклу, який використовує кожен, як і я всередині 3-го параметра, і я також зменшуюсь безпосередньо в масиві.

Це сказав, що це підтверджує, що такі машини, як

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

for(
 var i = array.length ;
 i-- ;
 arrayCopy[ i ] = array[ i ] // doing stuff
);

Навіть якщо це коротше, схоже, що використання ще iодного разу сповільнює все. Це на 1/5 повільніше, ніж попередній forцикл і той while.

Примітка:; дуже важливо після того , як для looo без{}

Навіть якщо я щойно сказав вам, що jsperf - це не найкращий спосіб тестування скриптів .. я додав сюди дві петлі

http://jsperf.com/caching-array-length/40

І ось ще одна відповідь про продуктивність у javascript

https://stackoverflow.com/a/21353032/2450730

Ця відповідь полягає в тому, щоб показати виконавські способи написання JavaScript. Тож якщо ви не можете цього прочитати, запитайте, і ви отримаєте відповідь або прочитаєте книгу про Javascript http://www.ecma-international.org/ecma-262/5.1/


Ця відповідь починається дуже добре . Я помітив, що останні пару років forбуло швидше, ніж whileколись, і я одного разу прочитав на crome-dev саме через причину, яку ви згадуєте. Було б лише питання часу, перш ніж whileзнову наздожене. З цього моменту логіка в першій частині вашої відповіді буде дотримуватися (ще раз, так)! Однак сучасні реалізації вже не суворо дотримуються кожного кроку, визначеного ecma (вони оптимізують). Оскільки тепер ваш двигун вже не є найбільш помітною горловиною, тепер фактично можна помітити кеш-пропуски процесора у зворотному циклі !
GitaarLAB

Поясніть, тому, можливо, я можу виправити відповідь або дізнатися щось нове. btw відповідь тепер вже більше року ... браузери, можливо, з часом змінилися, як завжди ...
cocco

На мою думку, в той час як (-length) є злом, оскільки, якщо це технічно працює, тому що 0 є хибним, 0 і false - це насправді не те саме, що семантично говорити.
scott.korin

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

9
"машини віддають перевагу цьому" звучить як пропозиція з оголошення прального порошку
CocoaBean

11

http://jsperf.com/caching-array-length/60

Остання редакція тесту, яку я підготував (повторно використовуючи старіший), показує одне.

Довжина кешування не так важлива, але це не шкодить.

Кожен перший запуск тесту, зв'язаного вище (на щойно відкритій вкладці), дає найкращі результати за останні 4 фрагменти (3-й, 5-й, 7-й та 10-й у діаграмах) у Chrome, Opera та Firefox в 64-розрядному Debian Squeeze ( моє обладнання для настільних ПК) ). Подальші пробіги дають зовсім інший результат.

Висновки щодо ефективності прості:

  • Перейдіть за циклом (вперед) і тестуйте, використовуючи !==замість <.
  • Якщо вам не доведеться використовувати масив пізніше, тоді цикл на зменшену довжину і shift()масив- деструктивний масив також ефективний.

тл; д-р

На сьогодні (2011.10) наведений нижче зразок виглядає як найшвидший.

for (var i = 0, len = arr.length; i !== len; i++) {
    ...
}

Зверніть увагу, що кешування arr.lengthтут не є вирішальним, тому ви можете просто протестувати i !== arr.lengthта продуктивність не знизиться, але ви отримаєте коротший код.


PS: Я знаю, що в фрагменті з shift()його результатом можна використовувати замість доступу до 0-го елемента, але я якось не помітив, що після повторного використання попередньої редакції (яка мала помилки під час циклів), а пізніше я не хотів втрачати вже отримані результати.


Створення змінної insie циклу, як нехай current = arr [i] може зменшити продуктивність (великий розподіл пам'яті)? Або краще оголосити струм перед циклом? Або використовувати arr [i] в ​​усіх місцях всередині циклу?
Макаров Сергій

8

"Найкраще" як у чистому виконанні? або виконання І читабельність?

Чиста продуктивність "найкраща" - це це, що використовує кеш і оператор префікса ++ (мої дані: http://jsperf.com/caching-array-length/189 )

for (var i = 0, len = myArray.length; i < len; ++i) {
  // blah blah
}

Я заперечую, що без кеш-пам'яті для циклу - найкращий баланс у часі виконання та час читання програміста. Кожен програміст, який розпочав роботу з C / C ++ / Java, не витрачатиме повідомлення, прочитавши цей

for(var i=0; i < arr.length; i++){
  // blah blah
}

2
+1 для читабельності. Незалежно від того, наскільки добре lenназвано, завжди потрібно було б подвоїти цю першу петлю. Намір другого циклу очевидний.
Джош Джонсон

7

** Кешуйте довжину масиву всередині циклу, деякі секунди часу будуть ухилятися. Залежить від елементів у масиві, якщо в масиві є більше елементів, є велика різниця щодо Ms часу *

**

sArr; //Array[158];

for(var i = 0 ; i <sArr.length ; i++) {
 callArray(sArr[i]); //function call
}

***end: 6.875ms***

**

**

sArr; //Array[158];
for(var i = 0,len = sArr.length ; i < len ; i++) {
  callArray(sArr[i]); //function call
}

***end: 1.354ms***

**


6

Це, здається, найшвидший спосіб на сьогодні ...

var el;
while (el = arr.shift()) {
  el *= 2;
}

Враховуйте, що це буде споживати масив, з'їдаючи його, і нічого не залишаючи ...


2
arr.shift();замість того, arr.pop() щоб можна було уникнути реверсу масиву.
Tintu C Raju

1
@Gargaroz, якщо ви отримуєте JSON від веб-сервісу, наприклад, служби чату або предметів у каталозі товарів. Іншою ситуацією, коли вам просто потрібно використовувати масив один раз, може бути, наприклад, діаграма, яка отримує багато координат на внутрішній основі. Прикладів багато.
Серхіо

Класно, дякую за пояснення, дуже люб’язно з вас; чи можете ви вказати мене в тому напрямку, де я можу знайти подальші приклади для використання цього циклу?
Гаргароз

1
В даний час в Chrome 53 і Firefox 48 це один з найбільш повільного підходу - перевірка на perfjs.info/array-iteration
моряк

1
@Alireza погоджуюся, я маю коментар до цього і у своїй відповіді.
Серхіо

4

Це 2017 рік .

Я зробив кілька тестів.

https://jsperf.com/fastest-way-to-iterate-through-an-array/

Схоже, whileметод найшвидший у Chrome.

Схоже , лівий декремента ( --i) набагато швидше , ніж інші ( ++i, i--,i++ ) на Firefox.

Цей підхід є голодним в середньому. Але це повторює масив у зворотному порядку.

let i = array.length;
while (--i >= 0) {
    doSomething(array[i]);
}

Якщо форвардний порядок важливий, використовуйте такий підхід.

let ii = array.length;
let i = 0;
while (i < ii) {
    doSomething(array[i]);
    ++i;
}

3
Використовуючи ключове слово, letви фактично порівнюєте продуктивність створення області замість продуктивності циклу. Використання let i = 0, ii = array.lengthв forциклі створить нову область для цих змінних всередині forблоку. Ваші whileприклади не створюють нову область для змінних всередині whileблоку, і тому вони швидші. Якщо ви використовуєте varзамість цього letдля циклів, ви побачите, як петлі все ще такі швидкі, як батоги в 2017 році, але читабельніші.
CGodo

Ось jsperf того, про що я говорю: jsperf.com/javascript-loop-testing-let-vs-var
CGodo

Це лише проблема в Chrome. В інших браузерах varі letмають таку ж продуктивність - stackoverflow.com/a/32345435/1785975
SeregPie

Цікаво. У будь-якому разі, я не вважаю твердження " whileшвидше працювати в Chrome". Це лише за умови використання letчерез проблеми з ефективністю цього ключового слова в Chrome. Якщо ви користуєтесь varабо з іншими браузерами, forі whileмайже однакові, іноді forнавіть швидше, залежно від еталону, і він є більш компактним і читабельним imho.
CGodo

2

Я завжди пишу в першому стилі.

Навіть якщо компілятор досить розумний, щоб оптимізувати його для масивів, але все-таки він розумний, якщо ми тут використовуємо DOMNodeList або якийсь складний об'єкт із розрахунковою довжиною?

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


1
var arr = []; // The array
var i = 0;
while (i < arr.length) {
    // Do something with arr[i]
    i++;
}

i ++ швидше, ніж ++ i, --i та i--

Крім того, ви можете зберегти останній рядок, виконуючи arr [i ++] в останній раз, коли вам потрібно отримати доступ до i (але це може бути важко налагодити).

Ви можете протестувати його тут (за допомогою інших тестів циклу): http://jsperf.com/for-vs-partpop/5


1
Наразі в Chrome 53 це правда, але Firefox 48 має таку ж швидкість - перевірте на perfjs.info/array-iteration
моряк

thunderguy.com/semicolon/2002/08/13/… каже ++i, що швидше ...
IMTheNachoMan

1

З вересня 2017 року ці тести на jsperf демонструють таку схему, яка є найбільш ефективною у Chrome 60:

function foo(x) {
 x;
};
arr.forEach(foo);

Хтось здатний відтворити?


Так, це здається найшвидшим, проте спробуйте запустити це в IE11, і ці варіанти є найповільнішими. А у Firefox 55.03 «старий розбитий кешований простір» досягає 12 мільйонів, що є приголомшливою продуктивністю порівняно з 3,3 тис. Хромованих. Щоб бути послідовною у всіх браузерах, ви повинні використовувати найшвидший середній цикл для кожного браузера.
Plippie

0

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

var firstHalfLen =0;
var secondHalfLen = 0;
var count2=0;
var searchterm = "face";
var halfLen = arrayLength/2;
if(arrayLength%2==halfLen)
{
   firstHalfLen = Math.ceil(halfLen);
   secondHalfLen=Math.floor(halfLen);
}
else
{
   firstHalfLen=halfLen;
   secondHalfLen=halfLen;
}
for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen;
    firstHalfCOunter < firstHalfLen;
    firstHalfCOunter++)
{
  if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1)
  {
    count2+=1;
  }
  if(secondHalfCounter < arrayLength)
  {
    if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1)
    {
        count2+=1;
    }
    secondHalfCounter++; 
  }
}

Деякі порівняння продуктивності (використовуючи timer.js) між кешованою довжиною для циклу VS за описаним вище способом.

http://jsfiddle.net/tejzpr/bbLgzxgo/


0

Ще один тест jsperf.com: http://jsperf.com/time-reverse-vs-for-cached-length

Зворотний цикл, хоча цикл, здається, найшвидший. Проблема полягає лише в тому, що поки (--i) зупиниться на 0. Як я можу отримати доступ до масиву [0] у своєму циклі?


2
Якщо ви це зробите, while (i--)то правдивість iволі буде перевірена перед декрементацією, а не декрементацією, а потім випробуванням правдивості.
Джастін Фішер


0

Хоча цикл трохи швидший, ніж для циклу.

var len = arr.length;
while (len--) {
    // blah blah
}

Використовуйте натомість цикл



-1

Найелегантніше рішення, про яке я знаю, - це використання карт.

var arr = [1,2,3];
arr.map(function(input){console.log(input);});

46
Питання не в тому, щоб просити найповільнішого способу перегляду циклу
eoleary


-1

Швидший спосіб циклічного циклу - це використання фільтра. Метод filter () створює новий масив з усіма елементами, які проходять тест, реалізований наданою функцією.

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

const words = ['Floccinaucinihilipilification', 'limit', 'elite', 'Hippopotomonstrosesquipedaliophobia', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(new Date(), result);

Зі свого досвіду, я завжди віддаю перевагу фільтрам, картам тощо.


Питання полягає в ітерації над масивом за найкоротший час, а не про копіювання масиву в новий масив.
Рахул Кадукар

-1

Станом на 2019 рік WebWorker стає більш популярним, для великих наборів даних ми можемо використовувати WebWorker для обробки набагато швидше, повністю використовуючи багатоядерні процесори.

У нас також є Parallel.js, який значно спрощує використання WebWorker для обробки даних.

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