for vs forEach vs reduce
Бенчмарк трёх способов обойти массив. Главный вывод: цифры прыгают между запусками из-за деоптимизации на SMI.
forEachстабильно чуть медленнее,forиreduceплюс-минус равны в горячем коде.
Что измерял AsForJS
- Один и тот же
sumмассива черезfor,forEach,reduce. - Прогон по миллионам элементов, многократный запуск.
- Между запусками —
--trace-deoptдля понимания, где функция уходит в Ignition.
Почему числа прыгают
- Массив на ходу мог стать
holeyили сдвинутьсяSMI → Double. - При первом запуске IC ещё monomorphic, на втором — polymorphic.
- TurboFan мог деоптимизировать функцию
reduce-колбэка после первой кучи итераций.
var помогает оптимизатору
«Внутрь V8 добавили специальную оптимизацию, которая старается убрать из окружения... любой идентификатор, который не используется внутри самого тела этой функции.»
Используешь var в горячем коде, не возвращая замыкание наружу — V8 чистит окружение агрессивнее.
Замыкание удерживает память
Возвращаешь из функции другую функцию (закрытие) — весь объём захваченного scope залочен от GC, даже если используется один identifier.
// Плохой случай — bigData никогда не освободится
function make(bigData) {
return => 42; // bigData в скоупе, GC не очистит
}
Подводные камни
forEachвсегда вызывает функцию через apply — лишний накладной расход.- Hot-цикл на стрелке часто инлайнится, но не всегда.
- Реальное правило: используй
for/ofилиfor, если важна скорость;map/reduce/forEach— для читаемости при не-горячем коде.
Источники
- Производительность for, forEach и reduce · AsForJS · 2026-04-14
- Цитата: «Объём залоченной памяти растёт с размером Array.»
- Цитата: «V8 нарушает спеку ради оптимизации — добавили специальную оптимизацию, которая старается убрать из окружения любой идентификатор, который не используется внутри тела функции.»
- Сравнение JavaScript Array reduce с for statement · AsForJS · 2024-04-10
- JavaScript Беседы Reduce, For, Wasm · AsForJS · 2023-11-19