Чем опасен .reduce() в JavaScript

22 июля, 2021

Я всегда любил метод 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 производительности в браузере

© 2024, Built with Gatsby