Performance профилирование

При работе с Mapbox GL JS ключевым ограничением становится производительность WebGL-рендеринга и обработка геоданных в потоке браузера. Профилирование начинается с фиксации базовых метрик:

  • FPS (frames per second) — стабильность отрисовки сцены
  • CPU time main thread — нагрузка на основной поток
  • GPU frame time — время рендеринга кадра на видеокарте
  • Tile load time — скорость загрузки векторных тайлов
  • Style recalculation time — пересчёт стиля при изменениях источников
  • Memory usage — потребление памяти WebGL и JS heap

Особое значение имеет разрыв между CPU и GPU нагрузкой: падение FPS при низкой загрузке CPU часто указывает на перегрузку GPU (сложные шейдеры, избыточные слои, overdraw).


Инструменты браузерного профилирования

Основной инструмент анализа — вкладка Performance в Chrome DevTools.

Фиксируем следующие сигналы:

  • длительные tasks (>50 ms) в main thread
  • частые layout / paint операции
  • spikes в scripting time при взаимодействии с картой
  • garbage collection pauses

Важные техники:

  • запись профиля при pan/zoom (имитация интерактивной нагрузки)
  • выделение участка с максимальной деградацией FPS
  • анализ flame chart для выявления функций Mapbox GL JS и пользовательских обработчиков

Дополнительно используется вкладка Memory:

  • heap snapshots при зумировании карты
  • сравнение аллокаций при повторных изменениях стиля
  • поиск удерживаемых ссылок на GeoJSON объекты и DOM контейнеры

Встроенные инструменты отладки Mapbox GL JS

В Mapbox GL JS предусмотрены визуальные режимы диагностики:

  • map.showTileBoundaries = true — отображение границ тайлов
  • map.showCollisionBoxes = true — визуализация столкновений подписей
  • map.showOverdrawInspector = true — анализ перерисовки пикселей
  • map.repaint = true (в debug-сборках) — принудительное отслеживание перерисовок

Эти режимы позволяют выявлять:

  • избыточную загрузку тайлов
  • проблемы label collision (перегрузка символов)
  • области чрезмерного overdraw (наложение слоёв)

Дополнительно используется статистика:

  • map.getCanvas().getContext('webgl') для проверки состояния контекста
  • события render, idle, data для измерения жизненного цикла кадра
  • map.on('render', ...) как триггер профилирования кадров

Профилирование WebGL-рендеринга

Mapbox GL JS использует WebGL pipeline, где основная нагрузка приходится на GPU:

Ключевые источники деградации:

  • большое количество fill/extrusion слоёв
  • сложные expression в стиле (interpolate, match)
  • частые style.setData() обновления
  • excessive blending (полупрозрачные слои)

Методы диагностики:

  • Chrome GPU rasterization stats
  • chrome://gpu для проверки включения аппаратного ускорения
  • WebGL Inspector (сторонние инструменты)
  • анализ draw calls через RenderDoc (в продвинутых сценариях)

Особое внимание:

  • число draw calls растёт линейно с количеством слоёв
  • symbol layers (текст/иконки) имеют высокую стоимость batching
  • fill-extrusion требует тяжёлых фрагментных шейдеров

Сетевые узкие места

Векторные карты зависят от загрузки тайлов:

  • .pbf запросы
  • glyphs (шрифты)
  • sprites (иконки)
  • raster-dem (если используется рельеф)

Метрики:

  • time to first tile
  • cache hit ratio
  • количество параллельных запросов
  • размер тайлов при зуме

Типовые проблемы:

  • отсутствие HTTP caching headers
  • отсутствие CDN оптимизации
  • избыточные источники (sources duplication)
  • частые re-request при pan

Оптимизация:

  • уменьшение maxzoom у источников
  • агрегация слоёв в один source
  • использование vector tiles вместо GeoJSON

Структура стиля и влияние на FPS

Стиль в Mapbox GL JS напрямую влияет на производительность.

Критические факторы:

  • количество layers
  • количество sources
  • сложность expressions
  • использование filter expressions на больших наборах данных

Зависимости производительности:

  • линейный рост времени layout при увеличении слоёв
  • экспоненциальный рост стоимости symbol placement при плотных данных
  • перерасчёт style при каждом setFilter / setLayoutProperty

Рекомендации по диагностике:

  • измерение map.style._layers (внутренний слойный граф)
  • анализ зависимостей source → layer
  • минимизация динамических изменений стиля

GeoJSON и стоимость данных

GeoJSON как источник данных становится узким местом при больших объёмах:

Проблемы:

  • загрузка всего dataset в память
  • отсутствие векторной тайлизации
  • блокировка main thread при parse JSON
  • частые diff вычисления при setData()

Сценарии деградации:

  • более 50–100k features в одном source
  • frequent updates (реaltime tracking)
  • clustering без предварительной агрегации

Оптимизация:

  • переход на vector tiles
  • simplification геометрии (Douglas–Peucker)
  • использование clustering на уровне сервера
  • разделение data sources по zoom level

Память и утечки

Основные источники утечек:

  • неочищенные event listeners на map
  • удержание ссылок на GeoJSON объекты
  • накопление WebGL buffers при пересоздании источников
  • повторное создание map instance без destroy

Методы диагностики:

  • heap snapshots (Chrome DevTools)
  • сравнение retained size между состояниями карты
  • анализ detached DOM trees
  • проверка WebGL resources growth

Типовой анти-паттерн:

  • регулярный вызов new mapboxgl.Map() без map.remove()

Интерактивные сценарии и нагрузка

Профилирование должно учитывать реальные сценарии:

  • continuous pan/zoom (drag interaction)
  • rapid style switching
  • hover-based feature queries
  • animation layers (transition, flyTo)

Ключевые точки измерения:

  • время ответа на move
  • latency между input event и render
  • frame drop rate при анимациях

Методика:

  • автоматизация через Puppeteer
  • запись performance trace под нагрузкой
  • сравнение cold start vs warm cache

Частые причины падения производительности

  • избыток symbol layers (текст + иконки)
  • отсутствие ограничений maxzoom/minzoom
  • heavy filters по большим datasets
  • частые вызовы setData
  • использование прозрачных слоёв с blending
  • отсутствие tile caching стратегии
  • перегруженные expressions в paint/layout

Практика изоляции узких мест

Последовательная стратегия профилирования:

  1. Проверка FPS без пользовательских слоёв
  2. Добавление источников по одному
  3. Фиксация момента деградации
  4. Изоляция слоя или source
  5. Проверка сетевых метрик отдельно от render
  6. Сравнение WebGL load vs CPU load

Такой подход позволяет отделить:

  • rendering bottleneck
  • data bottleneck
  • network bottleneck
  • style computation bottleneck