![](https://habrastorage.org/webt/ai/z5/gz/aiz5gztttvvkegk_annvvgtumv8.png)
Разные трюки я тестировал на Google Chrome 107.0.5304.107 и Mozilla Firefox 107.0 на Windows 10.
Чтобы результаты всегда были железно воспроизводимыми, я отключил все С-State’ы, ядра зафиксировал на 5 ГГц.
У меня 9900К, это Coffee Lake c AVX256, какие оптимизации применит Jit для вашего процессора — я не знаю, результат на вашем компьютере может отличаться от моего, в т.ч. из-за микроархитектуры процессора.
Скорость парсинга кода тоже входит в бенчмарк, поэтому браузер с быстрым парсером будет впереди.
Есть ли у переменной оверхед?
Есть ли смысл использовать только dot notation? Какова цена выноса лишней переменной?
var array = new Array(65535).fill()
// 3
var a = array.map((x) => x)
var b = array.map((x) => x)
var c = array.map((x) => x)
// 2
var a = array.map((x) => x)
var b = array.map((x) => x).map((x) => x)
// 1
var a = array.map((x) => x).map((x) => x).map((x) => x)
Чтобы узнать, гоняет ли браузер память туда-сюда, делаем мы
.map
на массив длиной 65535 с нулями внутри. Линк.![](https://habrastorage.org/webt/jw/ux/as/jwuxasvbrmoo8bd08xz23xqzbmk.jpeg)
Хром не заметил разницы, а вот лиса заметила. Применительно к лисе, у лишней переменной есть измеряемый оверхед.
Есть ли разница между var, let, const или их отсутствием?
![](https://habrastorage.org/webt/98/bq/py/98bqpyb07ylqtmillpqva2ol6d8.jpeg)
Проверим. Используя разные биндинги — создадим POJO с переменной
е
. Потом добавим ему функцию о
и запустим эту функцию. Бенчмарк простой, но движущихся частей много. Линк.var g = { e: [] }
g.o = function(x) { g.e.push(...[1,2,3]) }
g.o()
Код выглядит так, отличаются только биндинги.
![](https://habrastorage.org/webt/ll/t8/wc/llt8wc8317gsft-b-3hzsquks-u.jpeg)
Результат неожиданный, но железно воспроизводимый.
var
, быстрее.Bounce pattern, Switch case, длинная тернарка
Если обе конструкции логически одинаковые, они должны строить одно и то же синтаксическое дерево, верно? Давайте проверим.
// switch case
function thing(e) {
switch (e) {
case 0:
return "0";
case 1:
return "1";
case 2:
return "2";
case 3:
return "3";
default:
return "";
}
}
// bounce pattern
function bounce(x)
{
if (x === 0) return "0";
if (x === 1) return "1";
if (x === 2) return "2";
if (x === 3) return "3";
return ""
}
// ternary
function bounce(x) {
return 0 === x ? "0" : 1 === x ? "1" : 2 === x ? "2" : 3 === x ? "3" : "";
}
Вот так выглядит код. Для всех вариантов он одинаков, отличаются только вызовы.
▍ 1. Вызов в цикле
for (let t = 0; 1e5 > t; t++) bounce(0), bounce(2), bounce(6);
Вызов выглядит так. Линк.
![](https://habrastorage.org/webt/5z/c4/an/5zc4anssaguhuexso36fsymxo1w.jpeg)
▍ 2. В цикле с другим типом
for (let t = 0; 1e5 > t; t++) bounce("0"), bounce("2"), bounce("");
Тут мы покидываем строку вместо числа. В свитче и
if
блоках используется строгое равенство, поэтому свитч выходит только через default
, а if
’ы выходят только последний return
. Линк.![](https://habrastorage.org/webt/ce/a5/mo/cea5mooydemdi4kzpf2v8wtphjs.jpeg)
▍ 3. Без цикла
bounce(0), bounce(2), bounce(6)
Просто три вызова подряд, никаких циклов. Линк.
![](https://habrastorage.org/webt/8-/i5/p4/8-i5p4n-v3fvcckb41o7aue2a-m.jpeg)
Похоже, что после первоначальной компиляции лиса не пытается дальше оптимизировать цикл, как это делает хром.
Также лиса, похоже, не строит одно и то же AST, как это делает хром. Рекомендую заменить ваши длинные
if
’ы и bounce паттерны на свитчи, чтобы избежать лисиных тормозов.Инициализация массива
Для примера возьму из паттернов функционального программирования, когда ты инициализируешь массив, прокидывая лямбду в инициализатор. Просто ради примера, в качестве этой лямбды будет fizzbuzz.
var times = 65535;
function initializer(val, z) {
const i = z % 5 | 0;
return 0 == (z % 3 | 0) ? 0 === i ? "fizzbuzz" : "fizz" : 0 === i ? "buzz" : z;
}
// for i
var b = new Array(times);
for (var i = 0; i < times; i++) {
b[i] = initializer(b[i], i)
}
b
// for push
var c = [];
for (var i = 0; i < times; i++) {
c.push(initializer(c[i], i))
}
c
// Fill Map
new Array(times).fill().map(initializer)
Это не самый красивый fizzbuzz, но это мой fizzbuzz. Линк на бенч.
![](https://habrastorage.org/webt/2u/ms/at/2umsat5-a9manougryyx3iohjhq.jpeg)
Вариант с
fill map
создаёт два массива, сначала при вызове конструктора, потом при вызове map. Но такой вариант безальтернативно быстрее на хроме.Конкатенация массивов
![](https://habrastorage.org/webt/8k/uq/b0/8kuqb0dhvsvodnu0djtqvmn_aoe.jpeg)
// reduce
arr.reduce((acc, val) => acc.concat(val), [])
// flatMap
arr.flatMap(x => x)
// flat
arr.flat()
// reduce push
arr.reduce((acc, val) => {
if (val) val.forEach(a => acc.push(a));
return acc;
}, [])
// forEach push
let acc = [];
arr.forEach(val => {
val && val.forEach(v => acc.push(v));
}), acc;
//concat spread
[].concat(...arr)
Конкатенация массивов на 1 уровень, поведение идентичное
flat(1)
. Линк.![](https://habrastorage.org/webt/ey/_-/hs/ey_-hsu2gbykaalxdwgvpg_itr0.jpeg)
Иногда я не понимаю, почему разработчики движков оставили такой потенциал для оптимизации.
Уничтожение хрома
Бенчмарки ниже я перепроверял по нескольку раз, результат одинаковый и верный. Лиса действительно такая быстрая.
▍ Итерация по массиву
Сравнивать будем
Array.prototype.forEach vs for...of vs for
. На код смотрите по линку.![](https://habrastorage.org/webt/po/ue/fz/pouefzncq6xggwoxqyfnoy38wng.jpeg)
Ради производительности, циклы
for
, лучше переделать в forEach
, чтобы хром не отставал.▍ Содержит ли строка значение
// text.includes()
url.includes('matchthis')
// text.test()
/matchthis/.test(url)
// text.match()
url.match(/matchthis/).length >= 0
// text.indexOf()
url.indexOf('matchthis') >= 0
// text.search()
url.search('matchthis') >= 0
![](https://habrastorage.org/webt/4f/2l/4-/4f2l4-2wfg-pabfjrpgom4yx_ny.jpeg)
Трюк с
IndexOf
быстрее и на лисе, и на хроме. Используйте трюк с IndexOf
. Линк на бенчмарк.Преобразование строки в число
Тестируем неявное преобразование, парсинг и вызов конструктора.
// implicit
var imp = + strNum
// parseFloat
var toStr = parseFloat(strNum)
//Number
var num = Number(strNum)
▍ Int
![](https://habrastorage.org/webt/8b/0g/rb/8b0grbqwue2slct2x4gc95sy4nc.jpeg)
Линк на бенч.
▍ Float
![](https://habrastorage.org/webt/8b/0g/rb/8b0grbqwue2slct2x4gc95sy4nc.jpeg)
Я перепроверял, это не ошибка. Неявный каст стринги в инт практически бесплатный у лисы. Линк на бенч.
Выводы
- Лисичка похорошела.
- JS сделан за неделю на коленке.
- Я не пишу на JS.
- Вы тоже прекращайте.
Играй в нашу новую игру прямо в Telegram!
![](https://habrastorage.org/webt/sz/7j/pf/sz7jpfj8i1pa6ocj-eia09dev4q.png)