Я всегда любил метод reduce в JavaScript, потому что от давал возможность сделать очень гибкие преобразования всего, что угодно хоть объекта, хоть массива за 1 цикл.
И недавно в офисе я услышал мысль, что .reduce() работает очень медленно, и иногда лучше написать два цикла подряд. Например filter и map. Провёл эксперименты и удивился.
Вариант 1
Допустим есть такой код
const arr = [];
for (let i = 0; i < 100000; i++) {
arr.push(i);
}
let time = performance.now();
arr.map((i) => i + 1).filter((i) => i % 2 === 0);
time = performance.now() - time;
console.log(`Время выполнения = ${time}`);
Заполняем массив от 0 до 100 000.
1й цикл - прибавляем ко всем числам 1.
2й цикл - фильтруем чётные числа.
Время выполнения - 6 мс.
Вариант 2. Теперь пробуем уместить всё в один цикл с помощью Reduce
arr.reduce((acc, value) => {
const newValue = value + 1;
return newValue % 2 === 0 ? [...acc, newValue] : acc;
}, []);
Попробуйте представить время выполнения, оно ведь должно сократиться? Ведь мы всё делаем в одном цикле.
Время выполнения - 3 289 мс!!!
Я писал эту заметку, изначально использовав в коде 1 млн элементов. Но мне не хватило терпения дождаться окончания выполнения на миллионе элементов, там точно больше 1й минуты, поэтому убавил количество до 100к.
Вариант 3. Теперь заменим в коде массив на объект
arr.reduce((acc, value) => {
const newValue = value + 1;
return newValue % 2 === 0 ? { ...acc, newValue: true } : acc;
}, {});
Время выполнения - 3 мс.
Из за чего получился такой огромный результат в случае 2?
На каждом шаге - создаётся новый массив и старый копируется в новый. Поэтому сложность равняется 0(n^2)
Видео, если лень читать:
Моё видео на YouTube - Чем опасен .reduce() у массивов в JavaScript. Оптимизация Web производительности в браузере