Ловите
Кратко, что делать, если фронтенд лагает, а запросы с бекенда в порядке и быстро приходят:
Идете смотреть сборщик мусора
Потом смотрите утечки памяти
Потом уже ищите долгие функции на вкладке Main
Смотрите перерендеры реакт-компоненов
А теперь подробно
Почему вообще появляются лаги
Тормоза происходят из-за того, что JS-вычисления занимают слишком много времени и не попадают в размер кадра. Если вычисления занимают чуть больше одного кадра — будет лаг. Если вычисления не прекращаются вообще — будет фриз.
Сборка мусора
Как вычислить
Открыть вкладку «Performance», записать загрузку страницы.
Посмотреть скачки в памяти и выделить фрагмент, где есть скачок.
Открыть «Event Log», найти вкладки, где есть слово «GC» (Garbage Collection).
Сложить время всех вкладок GC. Если сборка мусора условно больше 50 мс, то это проблемка.
Почему так происходит
Сборка мусора происходит, когда движок понимает, что память закончилась и нужно освободить место.
Например, у нас есть список комментариев с пагинацией. Мы показали на странице 10000 комментариев. Нажимаем на вторую страницу и начинаем скроллить. Контейнер со списком очищается и загружаются следующие 10000 комментариев. Памяти не хватает, запускается сборщик мусора. Комментариев много, поэтому очистка занимает время → вычисления будут занимать больше одного кадра, поэтому при скролле будут лаги.
Плюс лаги еще могут быть, если на странице ну очень много элементов и мы начинаем скроллить. В этот момент браузер пересчитывает положение всего DOM-дерева на странице.
Как исправить
Уменьшить объем вычислений
Грузить меньше контента. Если мы понимаем, что в экран помещается 4 комментария, загрузить 20, а потом при скролле догрузить еще.
Еще можно запоминать константные вычисления в переменные, чтобы каждый не пересчитывать.
Использовать throttle
Если событие выполняется слишком часто, то можно выполнять пореже. Например, для бесконечной подгрузки комментариев стоит затротлить событие onscroll.
Отдать вычисления на видеокарту
Для анимации элементов использовать transform или opacity. Добавить свойство will-change или translateZ(0).
Отдать вычисления на сервер
На сервере машина мощнее, плюс сервер может использовать другой язык программирования, предназначенный для решения определенных задач, которые тяжело сделать в браузере на JS.
Отдать вычисления в ServiceWorker
Сервис-воркер выполняется в отдельном потоке, поэтому разгрузит ваш.
Утечка памяти
Как вычислить
Открыть вкладку «Performance», записать загрузку страницы.
Увидеть, что сборщик очищает намного меньше, чем копит память.
Почему так происходит
Сборщик мусора не удаляет объекты, т.к. считает, что они еще могут использоваться. Или оставили в DOM ненужные элементы.
Например, мы решили сделать 3D-модель телефона на свг. При повороте мышкой рисуем новый свг, добавляем в DOM, а старый забываем почистить → утечка памяти.
Или сделали компонент с отображением фотографии, в котором глобально подписываемся на все кнопки на странице (не знаю, зачем, просто пример).
Добавили на страницу список фотографий с пагинацией, наплодили подписок. Потом решили перейти на вторую страницу — очистили контейнер с фотографиями и добавили новые, а старые подписки не удалили → сборщик мусора не удаляет подписки, память заполняется.
Как исправить
Очищать ненужные события, чистить DOM, не оставлять ссылок.
Отдать вычисления на видеокарту
Если вернуться к примеру с 3D-моделью телефона, то анимацию можно переделать на канвас. Это поможет, потому что:
Все элементы свг хранятся в DOM и пересчитываются в памяти. Даже если мы добавим transform: translateZ(0), то это не поможет, т.к. координаты все равно будут пересчитываться в памяти и тупо отрисовываться на странице. То есть в translateZ(0) просто нет смысла.
Канвас отрисовывает сразу, не используя память, потому что все полученные объекты сразу превращаются в пиксели. Вся отрисовка происходит на видеокарте. Даже если мы забудем очистить холст, по FPS все будет ок.