Производительность цикла JavaScript - почему уменьшение итератора до 0 быстрее, чем увеличение - PullRequest
61 голосов
/ 19 августа 2010

В своей книге Даже более быстрые веб-сайты Стив Саундерс пишет, что простой способ улучшить производительность цикла - уменьшить итератор до 0, а не увеличивать его до общей длины ( на самом деле глава написана Николаем Ч. Закасом ). Это изменение может привести к экономии до 50% от первоначального времени выполнения, в зависимости от сложности каждой итерации. Например:

var values = [1,2,3,4,5];
var length = values.length;

for (var i=length; i--;) {
   process(values[i]);
}

Это почти идентично для цикла for, цикла do-while и цикла while.

Мне интересно, с чем это связано? Почему уменьшать итератор намного быстрее? (Мне интересны технические основы, а не тесты, подтверждающие это утверждение.)


РЕДАКТИРОВАТЬ: На первый взгляд используемый здесь синтаксис цикла выглядит неправильно. Нет length-1 или i>=0, поэтому давайте уточним (я тоже растерялся).

Вот общий синтаксис цикла:

for ([initial-expression]; [condition]; [final-expression])
   statement
  • начальное выражение - var i=length

    Это объявление переменной вычисляется первым.

  • состояние - i--

    Это выражение вычисляется перед каждой итерацией цикла. Он будет уменьшать переменную до первого прохождения цикла. Если это выражение оценивается как false, цикл заканчивается. В JavaScript это 0 == false, поэтому, если i в итоге равно 0, оно интерпретируется как false и цикл заканчивается.

  • * ** 1 049 1050 * окончательное выражение * ** 1052 одна тысяча пятьдесят-одна *

    Это выражение вычисляется в конце каждой итерации цикла (перед следующей оценкой условие ). Это не нужно здесь и пусто. Все три выражения являются необязательными в цикле for.

Синтаксис цикла for не является частью вопроса, но, поскольку он немного необычен, я думаю, что это интересно прояснить. И, возможно, одна из причин, почему он быстрее, заключается в том, что он использует меньше выражений («трюк» 0 == false).

Ответы [ 11 ]

1 голос
/ 19 августа 2010

Я провел тест на C # и C ++ (схожий синтаксис). Там, на самом деле, производительность существенно отличается в for циклах по сравнению с do while или while. В C ++ производительность увеличивается при увеличении. Это также может зависеть от компилятора.

Я считаю, что в Javascript все зависит от браузера (движок Javascript), но такое поведение следует ожидать. Javascript оптимизирован для работы с DOM. Итак, представьте, что вы просматриваете коллекцию элементов DOM, которые вы получаете на каждой итерации, и увеличиваете счетчик, когда вам нужно их удалить. Вы удаляете элемент 0, затем элемент 1, но затем пропускаете тот, который занимает место 0. При обратном цикле эта проблема исчезает. Я знаю, что приведенный пример не является правильным, но я действительно сталкивался с ситуациями, когда мне приходилось удалять элементы из постоянно меняющейся коллекции объектов.

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

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