Императивный код и процессор
Императивный код «легко ложится на процессор» — потому что транслируется в линейные машинные инструкции с минимумом косвенности. Декларативный (через массивы методов и закрытий) — дороже.
Почему императив быстрее на CPU
- Cache-friendly — данные обходятся последовательно.
- Branch prediction — простые ветвления хорошо предсказываются.
- Inlining — V8 чаще инлайнит простые императивные функции.
- Меньше слоёв косвенности → меньше cache misses.
Пример
// Декларатив: 3 промежуточных массива, 3 прохода, 3 функции колбэков
const sum = arr.filter(x => x > 0).map(x => x * 2).reduce((a, b) => a + b, 0);
// Императив: 1 проход, 0 промежуточных массивов
let s = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] > 0) s += arr[i] * 2;
}
В горячем коде разница может быть 5-10x на больших массивах.
Не везде это win
- Декларативный код легче читать и тестировать.
- Современный V8 ИНОГДА сливает chain методов через оптимизатор — но не всегда.
- При маленьких N (до 100) разница в шуме.
Принцип Mechanical Sympathy
Понимай железо. Cache lines обычно 64 байта. Если структура больше — touching её провоцирует cache miss.
В JS это:
- Hidden class — лучше fixed shape (in-object properties помещаются в одну cache line).
- Массив SMI plain — последовательность 4-байтных целых, чудо для CPU.
for...ofс iterator protocol — лишний косвенный вызов.
Источники
- Как императивный код легко ложится на процессор · AsForJS · 2025-10-08
- Как не мешать интерпретатору сделать JavaScript код быстрым · AsForJS · 2025-11-09
- Optimizing JavaScript for fun and profit (review) · AsForJS · 2024-04-08