Какой самый быстрый способ перебрать массив в 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
}

Я просто хочу знать, какой способ лучше всего применять на практике?

wong2
источник
1
Также стоит обратить внимание на циклы
cloakedninjas
@ wong2 Этот тест от Browserdiet содержит более полную коллекцию альтернатив.
Доми
1
jsben.ch/#/y3SpC
EscapeNetscape
Улучшено в предыдущем jsben: jsben.ch/#/R6LbS
Corbfon
Можем ли мы ввести for ... ofцикл в этом конкурсе? Синтаксис кажется даже проще, чем цикл for без кэширования, и я хочу знать, стоит ли переходить на использование циклов for.
программист

Ответы:

339

После выполнения этого теста с большинством современных браузеров ...

http://jsben.ch/dyM52

В настоящее время самая быстрая форма цикла (и на мой взгляд самая синтаксически очевидная).

стандарт для цикла с кэшированием длины

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

}

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

jondavidjohn
источник
6
Интересно, что в IE9 это быстрее: for (var i = 0, len = myArray.length; i <len; ++ i) {} // префикс incr вместо постфикса
Кристофер Беннаж,
4
Посмотрите, предпочитают ли операторы префикса вместо постфикса другие причины использования ++i.
Беннет МакЭлви
4
Я тестировал, используя префиксный оператор, как предложил @BennettMcElwee, и он работает немного быстрее: for(var i=0, len=myArray.length; i<len; ++i) проверьте jsperf.com/caching-array-length/84
victmo
21
Вы должны быть осторожны, используя этот цикл. Я начал использовать его, и мне было трудно отследить ошибку из-за одной ошибки, которую я сделал. Если вы вложите две петли, как это: jsfiddle.net/KQwmL/1 . Вы должны быть осторожны, чтобы именовать переменную в двух циклах по-разному, иначе вторая петля заменит первую длину.
Руи Маркес
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 для полного сравнения

gnur
источник
1
Не забудьте использовать var(иначе lenстановится глобальной переменной). Кроме того, см. Jsperf.com/loops для большего количества тестов цикла.
Матиас Биненс
22
Посту блога, на котором основан этот ответ, уже почти 4 года, и за это время многое изменилось в js engine, см. Мой ответ ниже для обновленного сравнения.
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.
  • Цикл, использующий функцию обратного вызова (например, стандарт для forEach), был примерно в 10 раз медленнее, чем цикл for.

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

  • Если ваше приложение выполняет итерации по большому количеству элементов или ваш код цикла находится внутри функции, которая часто используется, ответом является простой цикл 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. Хотя я думаю, что сейчас это действительно не нужно:

    for (var i = 0, len = arr.length; i < len; i++) {
      // Do stuff with arr[i]
    }
CGodo
источник
Нет. jsbench.github.io/#67b13d4e78cdd0d7a7346410d5becf12 показывает, что самым быстрым является «Обратный цикл, неявное сравнение, встроенный код» (105 221 операций / сек), тогда как «Цикл, кэшированное значение, встроенный код» набрал всего 76 635 операций / сек (Chrome 38.0.2125.1). )
Fr0sT
@ Fr0sT Ваш эталонный тест - другой сценарий, проходящий массивы от индекса 1 до <= длины. Конечно, это приведет к разным результатам. Если вы попытаетесь обойти массивы с нулями с <length - что мне кажется, это обычный сценарий - вы обнаружите, что результаты лучше оптимизировать с помощью обычного цикла "for" (с длиной кэшируемой строки, которая немного быстрее).
CGodo
Kyopaxa изменила тесты на (0 <= i <длина), результаты те же. «Обратный цикл, неявное сравнение, вызов функции» набрал 365 копий / с, тогда как «Цикл, кэшированное значение, встроенный код» набрал 350 копий / с (FF 51)
Fr0sT
@ Fr0sT, если вы измените кешированные циклы for с нулями без равного сравнения, например for(let i=0, j=array.length; i < j; i++), цикл for for for значительно ускорится. В нескольких тестах, которые я запускал, он выигрывал, в большинстве случаев он был в пределах погрешности или в обратном цикле.
Исаак Б
1
@IsaacB и все, извините, я не заметил, что стенд довольно некорректен - все прямые циклы повторяют 1..length, в то время как обратные циклы повторяют length..0 (элемент arr [length] недопустим). Я исправил тесты, и теперь они показывают следующие результаты: «Цикл, встроенный код» 360,616 операций / сек ± 0,27%, «Цикл, кэшированное значение, встроенный код» 345,786 операций / сек ± 2,18% (Sic!) «Обратный цикл, неявное сравнение, встроенный код «322 640 операций в секунду ± 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(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>

nullqube
источник
3
@ Майконн, ты, наверное, хотел сказать «и это работает везде, кроме Opera Mini»
дуб
3
@Maykonn, которого нет в списке по умолчанию, потому что 0,18% всех пользователей имеют IE8, и вы не должны тратить время на его поддержку; в 2018 году это мертвая лошадь.
Дуб
1
Это определенно верно, если учесть всех пользователей по всему миру. Но, к сожалению, в определенных частях света IE8 актуален пока.
Майконн
1
Если позволите, не только разные браузеры будут иметь разные результаты с разными методами, но одни и те же браузеры будут иметь разные результаты с разными входами. Массив с большим числом только будет оптимизирован, а небольшой смешанный - нет.
Кайидо
1
@ Таллил Спасибо.
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, давайте сосредоточимся на этом при разработке для chrome».

Но теперь, в 2014 году, цикл while вернулся на хром. это в 2 раза быстрее, в других / старых браузерах это всегда было быстрее.

В последнее время я сделал несколько новых тестов. Теперь в реальном мире эти короткие коды ничего не стоят, и jsperf не может правильно выполнить цикл while, потому что он должен воссоздать array.length, что также требует времени.

Вы не можете получить фактическую скорость цикла while на jsperf.

вам нужно создать свою собственную функцию и проверить это с помощью window.performance.now()

И да ... нет, пока цикл просто быстрее.

Настоящая проблема на самом деле заключается в манипуляциях с dom / времени рендеринга / времени рисования или как вы хотите это назвать.

Например, у меня есть сцена холста, где мне нужно вычислить координаты и столкновения ... это делается между 10-200 микросекундами (не миллисекундами). для рендеринга всего требуется несколько миллисекунд. То же, что и в DOM.

НО

В loopнекоторых случаях есть еще один суперэффективный способ использования for ... например, для копирования / клонирования массива.

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

Обратите внимание на настройку параметров:

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

Сказал, что это подтверждает, что машины, как -

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

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

Даже если он короче, похоже, что использование еще iодного раза все замедляет. Это на 1/5 медленнее, чем предыдущий forцикл и whileодин.

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

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

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
Объясните, так что, возможно, я смогу исправить ответ или узнать что-то новое. Кстати, ответу уже более года ... браузеры, возможно, со временем изменились, как и всегда ...
cocco
На мой взгляд, while (--length) - зло, потому что, хотя технически это работает, потому что 0 - это ложь, 0 и false - это не совсем то же самое, что семантически говоря.
scott.korin
да ... сейчас это старая запись ... но да, мне нравится простота while. И наверняка, как вы упомянули об этом в обоих случаях, вам нужно знать, что писать. С другой стороны, у меня никогда не было необходимости зацикливать отрицательные числа.
Cocco
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-му элементу, но я почему-то упустил это из виду после повторного использования предыдущей ревизии (которая имела неправильные циклы while), и позже я не хотел терять уже полученные результаты.

przemoc
источник
Создание переменной внутри цикла, например let 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
}
valbaca
источник
2
+1 для читабельности. Независимо от того, насколько хорошо lenназван, всегда нужно сделать двойной цикл в первом цикле. Намерение второго цикла очевидно.
Джош Джонсон
7

** кешировать длину массива внутри цикла, несколько секунд времени будут исключены. Зависит от элементов в массиве, если в массиве больше элементов, есть существенная разница в отношении времени M *

**

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;
}

Примите во внимание, что это будет использовать массив, съедая его и ничего не оставляя ...

Sergio
источник
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;
}
SeregPie
источник
3
Используя ключевое слово, letвы фактически сравниваете производительность создания области вместо производительности цикла. Использование let i = 0, ii = array.lengthв ваших forциклах создаст новую область видимости для этих переменных внутри forблока. Ваши whileпримеры не создают новую область видимости для переменных внутри whileблока, и поэтому они быстрее. Если вы используете varвместо letсвоих циклов for, вы увидите, что циклы for по-прежнему такие же быстрые, как и в 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 здесь или какой-то сложный объект с вычисленной длиной?

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

Olegas
источник
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- whilepop/5

Forestrf
источник
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 «старый отключенный кэшированный len» достигает 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) между кешированной длиной цикла for VS описанным выше методом.

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

tejzpr
источник
0

Еще один тест на jsperf.com: http://jsperf.com/ while-reverse-vs-for-cached-length

Обратный цикл покажется самым быстрым. Единственная проблема в том, что while (--i) остановится на 0. Как я могу получить доступ к массиву [0] в моем цикле?

Мориц Шмитц против Хюльста
источник
2
Если вы это сделаете, while (i--)то правдивость iбудет проверена перед уменьшением, а не уменьшением, а затем проверяется на правдивость.
Джастин Фишер
0

Хотя цикл немного быстрее, чем для цикла.

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

Вместо этого используйте цикл while

Азар Зафар
источник
-1

Самое элегантное решение, которое я знаю, это использование карты.

var arr = [1,2,3];
arr.map(function(input){console.log(input);});
Дэн
источник
46
Вопрос не в том, чтобы задать самый медленный способ перебора цикла
eoleary
-1

Попробуй это:

var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}
Ли Бин Чжао
источник
-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 для обработки данных.

Stackia
источник