Быстрые итераторы, регулярные выражения и другие вкусности

В этом разделе собраны некоторые практические советы по производительности отдельных конструкций в JavaScript-движках в браузере.

Итераторы

Давайте рассмотрим, какой способ перебора элементов будет максимально быстрым в JavaScript. У нас есть несколько возможностей, ниже приведен полный вариант кода для тестирования.

<!– набор элементов для результатов тестирования –>
<p id=”test1″></p>
<p id=”test2″></p>
<p id=”test3″></p>
<p id=”test4″></p>
<p id=”test5″></p>
<p id=”test6″></p>

<script type=”text/javascript”>
// выбираем все элементы из DOM-дерева
var items = document.getElementsByTagName(“*”);
// кэшируем текущий размер DOM-дерева
var length = items.length;
// запоминаем текущий момент времени
var time = new Date().getTime();

// запускаем первый тест, обычный перебор элементов массива,
// запускается 10000 раз
for (var j=0; j<10000; j++) {
     for (var i=0; i<items.length; i++) { 
          var item = items[i]; 
     }
}
// выводим результат в подготовленный выше контейнер
document.getElementById(‘test1’).innerHTML =
“Простой цикл: ” + (new Date().getTime() – time);
time = new Date().getTime();

// кэшируем размер массива
for (var j=0; j<10000; j++) { 
     for (var i=0; i<length; i++) { 
          var item = items[i]; 
     }
}
document.getElementById(‘test2’).innerHTML =
“Простой цикл (с кэшированием): ” + (new Date().getTime() – time);
time = new Date().getTime();
// встроенный for-in итератор для объекта массива
for (var j=0; j<10000; j++) { 
     for (var i in items) { 
          var item = items[i]; 
     }
}
document.getElementById(‘test3’).innerHTML =
“Простой через for-in: ” + (new Date().getTime() – time);
time = new Date().getTime();
// обратный перебор элементов массива
for (var j=0; j<10000; j++) { 
     for (var i = length – 1; i >= 0; i–) { 
          var item = items[i]; 
     }
}
document.getElementById(‘test4’).innerHTML =
“Обратный: ” + (new Date().getTime() – time);
time = new Date().getTime();

// итератор do-while
for (var j=0; j<10000; j++) { 
     var i = 0; do { 
          var item = items[i]; i++; 
     } 
     while (i < length)
}
document.getElementById(‘test5’).innerHTML =
“do-while: ” + (new Date().getTime() – time);
time = new Date().getTime();

// обратный while (самый быстрый)
for (var j=0; j<10000; j++) { 
     var i = length – 1; while (–i) { 
          var item = items[i]; 
     }
}
document.getElementById(‘test6’).innerHTML = 
     “Обратный while: ” + (new Date().getTime() – time);
</script>

В результате мы получим примерно следующую таблицу.

Браузер

Обычный

С кэшем

for-in

Обратный

do-while

Обратный while

Firefox 3.0.3

714

657

835

280

297

217

Safari 3.1.2

141

140

157

125

125

93

Opera 9.61

188

125

765

94

94

78

IE 6

1281

1219

1094

468

500

360

IE 7

1391

1297

1250

515

532

406

IE 8b2

954

906

922

406

422

328

Chrome 0.2

288

246

332

117

114

95

Таблица 14. Различные варианты перебора массива, результаты в миллисекундах

В общем случае применение обратного while для перебора цикла в 2-3 раза быстрее всех остальных вариантов. Если веб-приложение оперирует массивами порядка 1000 элементов, то в результате примнения оптимизированных приемов будет заметен значительный прирост производительности.

Регулярные выражения

В JavaScript есть несколько способов проверить, удовлетворяет ли строка заданному шаблону:

// 1. Объявляем объект в виде регулярного выражения
var RegExp = ‘/script/gi’;
// и ищем в элементе массива совпадение с заданным шаблоном items[i].nodeName.search(RegExp);

// 2. можно просто проверять соответствие строке,  
// а не искать индекс подстроки
items[i].nodeName.match(RegExp);

// 3. Можно обойтись без объявления самого регулярного выражения
items[i].nodeName.match(/script/gi);

// 4. Можно задавать регулярное выражение без глобального модификатора,
// ведь мы ищем любое (=первое) совпадение шаблона
items[i].nodeName.match(/script/i);

// 5. С тем же успехом мы можем выполнить шаблон
/script/i.exec(items[i].nodeName);

// 6. Наконец, можно протестировать сам шаблон на нахождение в строке
/script/i.test(items[i].nodeName);

Давайте рассмотрим, что из них работает быстрее всего. Для этого запустим немного модифицированный набор тестов из раздела выше (опять по 10000 раз для всего DOM-дерева). Получим следующие результаты:

Как мы видим, в данном случае создание нового регулярного выражения – весьма ресурсоемкий процесс, поэтому в большинстве случаев лучше обходиться без него. В остальном все браузеры ведут себя достаточно ровно при сопоставлении match, exec и test.

 Браузер

search

match

«На лету»

Локальный

exec

test

Firefox 3.0.3

2120

2041

1295

1273

1225

1348

Safari 3.1.2

453

469

344

359

360

359

Opera 9.61

2141

2063

406

344

312

313

IE 6

2594

2516

1875

1859

1953

1906

IE 7

2562

2469

1859

1844

2000

1860

IE 8b2

2140

2032

1453

1453

1547

1469

Chrome 0.2

856

870

416

397

385

392

Таблица 15. Различные варианты выполнения регулярного выражения, результаты в миллисекундах

Материалы близкой тематики:

Posted in Разгони свой сайт.