Pull to refresh

Оптимизация JavaScript: Scope, Low level ES vs ES5 Array methods

Reading time 4 min
Views 2K
Сегодня мы будем тестировать 2 блока кода, выполняющие следующую операцию:
Дается массив, необходимо выбрать все элементы, степень 2 которых больше 5.

В синем углу Вариант А: Низкоуровневый код — старый и страшный (поддающийся частичной оптимизации)
  1.    for (i = 0, res = []; i < c; i++) {
  2.        t = a[i];
  3.        if (t >= 2.236067) {
  4.            continue;
  5.        } else {
  6.            res.push(t * t);
  7.        }
  8.    }

В красном углу Вариант Б: Высокоуровневый код — молодой и красивый (не поддающийся частичной оптимизации)
  1. a.map(function (t) { return t * t}).filter(function (t) { return t > 5});

Битвы будут происходить на 3 аренах.
1. AO args — Параметры объекта активации функции.
2. AO — Локальные переменные объекта активации функции.
3. Global — Глобальные переменные.



В арсенале у нас последние стабильные версии всех популярных браузеров.

Весь код теста:
  1.  
  2. // * * * * * * * * * * * * * * * * *
  3. // Activation object Arguments scope
  4. // * * * * * * * * * * * * * * * * *
  5.  
  6. (function (a, dt, index, i, c, r, t, res) {
  7. r = [];
  8. c = a.length;
  9.  
  10. dt = new Date();
  11. index = 20000;
  12. while (index--) {
  13.    a.map(function (t) { return t * t}).filter(function (t) { return t > 5});
  14. }
  15. r[0] = (new Date() - dt);
  16.  
  17. dt = new Date();
  18. index = 20000;
  19. while (index--) {
  20.    for (i = 0, res = []; i < c; i++) {
  21.        t = a[i];
  22.        if (t >= 2.236067) {
  23.            continue;
  24.        } else {
  25.            res.push(t * t);
  26.        }
  27.    }
  28. }
  29. r[1] = (new Date() - dt);
  30.  
  31. alert('ao args: ' + r);
  32. }([1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
  33.  
  34. // * * * * * * * * * * * * * * * * *
  35. // Activation object scope
  36. // * * * * * * * * * * * * * * * * *
  37.  
  38. (function () {
  39. var a = [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10],
  40.     dt,
  41.     index,
  42.     i,
  43.     c,
  44.     r,
  45.     t,
  46.     res
  47.     ;
  48.  
  49. r = [];
  50. c = a.length;
  51.  
  52. dt = new Date();
  53. index = 20000;
  54. while (index--) {
  55.    a.map(function (t) { return t * t}).filter(function (t) { return t > 5});
  56. }
  57. r[0] = (new Date() - dt);
  58.  
  59. dt = new Date();
  60. index = 20000;
  61. while (index--) {
  62.    for (i = 0, res = []; i < c; i++) {
  63.        t = a[i];
  64.        if (t >= 2.236067) {
  65.            continue;
  66.        } else {
  67.            res.push(t * t);
  68.        }
  69.    }
  70. }
  71. r[1] = (new Date() - dt);
  72.  
  73. alert('ao:      ' + r);
  74. }());
  75.  
  76. // * * * * * * * * * * * * * * * * *
  77. // Global scope
  78. // * * * * * * * * * * * * * * * * *
  79.  
  80. var a = [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10],
  81.     dt,
  82.     index,
  83.     i,
  84.     c,
  85.     r,
  86.     t,
  87.     res
  88.     ;
  89.  
  90. r = [];
  91. c = a.length;
  92.  
  93. dt = new Date();
  94. index = 20000;
  95. while (index--) {
  96.    a.map(function (t) { return t * t}).filter(function (t) { return t > 5});
  97. }
  98. r[0] = (new Date() - dt);
  99.  
  100. dt = new Date();
  101. index = 20000;
  102. while (index--) {
  103.    for (i = 0, res = []; i < c; i++) {
  104.        t = a[i];
  105.        if (t >= 2.236067) {
  106.            continue;
  107.        } else {
  108.            res.push(t * t);
  109.        }
  110.    }
  111. }
  112. r[1] = (new Date() - dt);
  113.  
  114. alert('global:  ' + r);
  115.  


Код: pastebin.com/mqBdkXZG

Результаты


FF high level low level
AO args 458 92
AO 474 122
Global 479 162
Opera high level low level
AO args 416 22
AO 427 21
Global 428 49
Chrome high level low level
AO args 83 9
AO 89 8
Global 98 28
Sa high level low level
AO args 153 21
AO 146 24
Global 147 25
IE8 high level low level
AO args выбыл 441
AO выбыл 393
Global выбыл 822

Итоги


Как видим, наблюдается тенденция AO args|AO быстрее Global. Это ясно из спецификации ECMAScript — обращение к переменным объекта активации быстрее потому, что он(АО) лежит «ближе к коду» чем глобальный объект.
Низкоуровневый код, в разы быстрее всокоуровневого потому что в ECMAScript нет блоков как в Ruby, для каждого элемента массива вызывается функция, а вызов функции затратная операция для JS. Высокоуровневый код медленнее до 20 раз!
Chrome такой быстрый потому что имеет JIT компилляцию, но для часто используемых блоков кода (1 прогон даст одинаковый результат).
Интересный момент показывает Firefox: AO args (low) 92; AO (low) 122; AO args на четверть быстрее. Хотя все эти переменные что AO args, что AO лежат в одном объекте, но в ФФ AO args, судя по результатам, выделяется в отдельный объект.

Ещё интересный тест.
  1. (function (r, dt, index, i, j) {
  2.  
  3. dt = new Date();
  4. index = 50000;
  5. while(index--) {
  6.  
  7. // Block A
  8.   for (i = 0, j= 0; i < 20; i++) {
  9.     j++;
  10.   }
  11. // -------
  12.  
  13. }
  14. r[0] = new Date - dt;
  15.  
  16. dt = new Date();
  17. index = 50000;
  18. while(index--) {
  19.  
  20. // Block B
  21.   j = 0;
  22.   j++;j++;j++;j++;j++;
  23.   j++;j++;j++;j++;j++;
  24.   j++;j++;j++;j++;j++;
  25.   j++;j++;j++;j++;j++;
  26. // -------
  27.  
  28. }
  29. r[1] = new Date - dt;
  30.  
  31. alert(r);
  32.  
  33. }([]));


Какой блок будет быстрее? Ответ: pastebin.com/hXxQb6pk

UPD В конечном итоге все упирается перерисовку интерфейса (reflow, redraw), однако, как показала моя практика, оптимизации reflow было не достаточно. Значительную часть съедали вызовы анонимных функций, устранив их был получен хороший прирост, особенно в древних браузерах, из-за которых мы и страдаем. Не воспринимайте эту статью как руководство к действию, пишите код как считаете удобным для вас. Я советую производить оптимизацию по необходимости.
Tags:
Hubs:
+1
Comments 29
Comments Comments 29

Articles