Javascript: Эффективен ли метод длины? - PullRequest
24 голосов
/ 07 марта 2012

Я делаю некоторое кодирование javascript, и мне было интересно, является ли метод длины "предварительно вычисленным" или запомнен механизмом JS.

Итак, вопрос:

Если я действительно часто проверяю длину массива и предполагаю, что я не изменяю его (делая его неизменным через замыкание), должен ли я предварительно вычислить метод длины и сохранить его в некоторой переменной?

Спасибо!

Ответы [ 5 ]

25 голосов
/ 07 марта 2012

Как всегда, ответ «все зависит».

Давайте протестируем собственные массивы с массивом из миллиона элементов:

for (var i = 0; i < arr.length; i++);

var len=arr.length;
for (var i = 0; i < len; i++);

http://josh3736.net/images/arrlen.png

Chrome и Firefox оптимизируют средство доступа к свойствам так же эффективно, как и копирование длины в локальную переменную.IE и Opera этого не делают, и на 50% + медленнее.

Однако , имейте в виду, что «ops / second» результатов теста означает число полных итераций в течениемассив из миллиона элементов в секунду.

Чтобы представить это в перспективе, даже в IE8 (худший результат в этом наборе) - который набрал 0,44 и 3,9 в доступе к свойству и локальной переменной (соответственно)- штраф за каждую итерацию был скудным 2 мкс .Итерация более тысячи элементов с использованием array.length обойдется вам только в дополнительные 2 мс.Другими словами: Остерегайтесь преждевременной оптимизации .

13 голосов
/ 07 марта 2012

Длина фактического массива не вычисляется на лету.Он хранится как часть структуры данных массива, поэтому для доступа к нему требуется не больше работы, чем просто выборка значения (нет вычислений).Таким образом, обычно это происходит так же быстро, как и извлечение любого фиксированного свойства объекта.Как вы можете видеть в этом тесте производительности, в принципе нет разницы между получением длины массива и получением свойства объекта:

http://jsperf.com/length-comparisons

Исключением являетсяобъект nodeList, который DOM возвращает из таких функций, как getElementsByTagName() или getElementsByClassName().В них часто гораздо медленнее получить доступ к свойству длины.Вероятно, это связано с тем, что эти объекты nodeList не являются настоящими объектами javascript, и между Javascript и собственным кодом может существовать мост, который необходимо пересекать каждый раз, когда к этим объектам получают доступ.В этом случае было бы НАМНОГО быстрее (в 10-100 раз быстрее) кешировать длину в локальную переменную, а не использовать ее многократно в цикле от нодлиста.Я добавил это к сравнению длины, и вы можете увидеть, насколько оно медленнее.

В некоторых браузерах значительно быстрее поместить длину в локальную переменную и использовать ее оттуда, если вы захотите.обращаться к нему снова и снова (как в цикле).Вот график производительности из приведенного выше теста jsperf:

8 голосов
/ 07 марта 2012

Все основные интерпретаторы предоставляют эффективные средства доступа для длин собственных массивов, но не для массивоподобных объектов, таких как NodeList s.

«Эффективное зацикливание в Javascript»

Test / Browser                Firefox 2.0 Opera 9.1   Internet Explorer 6
Native For-Loop               155 (ms)    121 (ms)    160 (ms)
...
Improved Native While-Loop    120 (ms)    100 (ms)    110 (ms)

«Эффективный код JavaScript» предлагает

for( var i = 0; i < document.getElementsByTagName('tr').length; i++ ) {
  document.getElementsByTagName('tr')[i].className = 'newclass';
  document.getElementsByTagName('tr')[i].style.color = 'red';
  ...
}

var rows = document.getElementsByTagName('tr');
for( var i = 0; i < rows.length; i++ ) {
  rows[i].className = 'newclass';
  rows[i].style.color = 'red';
  ...
}

Ни один из них не эффективен. getElementsByTagName возвращает динамический объект, а не статический массив. Каждый раз, когда проверяется условие цикла, Opera должна переоценивать объект и определять, сколько элементов оно ссылается, чтобы определить свойство length. Это занимает немного больше времени, чем проверка по статическому номеру.

2 голосов
/ 07 марта 2012

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

См. http://jsperf.com/for-loop-caching для элементарного тестового примера JSperf.

1 голос
/ 07 марта 2012

Для любого объекта типа коллекции, длиной которого вы не будете манипулировать (например, для любой неизменяемой коллекции), всегда полезно кэшировать его длину для повышения производительности.

var elems = document.getElementsByName("tst");
var elemsLen = elems.length;
var i;
for(i = 0; i < elemsLen; ++i)
{
  // work with elems... example:
  // elems[i].selected = false;
}
elems = [10,20,30,40,50,60,70,80,90,100];
elemsLen = elems.length;
for(i = 0; i < elemsLen; ++i)
{
  // work with elems... example:
  // elems[i] = elems[i] / 10;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...