При работе с Mapbox GL JS производительность нельзя свести к одному
числу. Система рендеринга построена на WebGL, использует асинхронную
загрузку тайлов, worker-потоки для парсинга данных и сложный пайплайн от
источника данных до пикселей на экране. Поэтому тестирование опирается
на набор взаимосвязанных метрик.
Ключевые показатели:
- FPS (frames per second) — стабильность отрисовки
сцены при взаимодействии
- Time to First Render (TTFR) — время до первого
отображения карты
- Time to Fully Loaded Map — момент, когда все тайлы
и стили загружены
- Tile Load Time — задержка загрузки и декодирования
векторных тайлов
- Memory usage (JS heap + GPU memory) — потребление
памяти браузером
- CPU usage — нагрузка на main thread и workers
- Interaction latency — задержка реакции на
pan/zoom/rotate
- Shader compile time — стоимость компиляции WebGL
программ
Каждая метрика должна рассматриваться в контексте сценария:
статическая карта, интерактивная навигация, анимации или плотные
дата-визуализации.
Архитектура, влияющая на
тестирование
Производительность Mapbox GL JS определяется несколькими слоями:
Main thread
- обработка событий пользователя
- управление состоянием карты
- orchestration рендеринга
Worker threads
- парсинг vector tiles (PBF)
- генерация геометрии
- подготовка данных для WebGL
GPU pipeline
- рендеринг слоёв
- выполнение шейдеров
- композиция кадров
Особенность тестирования в том, что узкое место может находиться в
любом из этих уровней, и классические JS-бенчмарки недостаточны.
Типовой подход к тестированию включает три уровня:
1. Synthetic benchmark
(искусственные сцены)
Используются контролируемые данные:
- фиксированное число источников (
sources)
- заранее заданное количество слоёв (
layers)
- одинаковый набор тайлов
- отключение сетевых вариаций через кеш
Цель — сравнение конфигураций без внешнего шума.
2. Real-world dataset testing
Используются реальные стили и данные:
- городские карты с высокой плотностью POI
- спутниковые слои + векторная подложка
- сложные выражения фильтров (
filter expressions)
- большое количество symbol layers
Цель — оценка поведения в реальных условиях.
3. Stress testing
Сценарии экстремальной нагрузки:
- десятки тысяч точек
- агрессивный clustering
- множественные animated layers
- частые camera updates (flyTo, easeTo)
- параллельная загрузка стилей
Измерение FPS и
стабильности рендеринга
FPS в WebGL-картах — не просто среднее значение, а распределение
кадров.
Важно измерять:
- mean FPS
- 1% low FPS (плохие кадры)
- frame jitter (дисперсия времени кадра)
Пример базового измерения:
let lastTime = performance.now();
let frames = 0;
let fpsValues = [];
function loop() {
const now = performance.now();
frames++;
if (now - lastTime >= 1000) {
fpsValues.push(frames);
frames = 0;
lastTime = now;
}
requestAnimationFrame(loop);
}
loop();
При анализе Mapbox GL JS важно учитывать, что падение FPS часто
связано не с рендерингом, а с:
- пересчётом layout symbol layers
- перекомпоновкой источников данных
- GC-паузами
Time to First Render (TTFR)
TTFR зависит от цепочки:
- загрузка JS-библиотеки
- создание WebGL контекста
- загрузка стиля
- загрузка sprite и glyphs
- первичная отрисовка тайлов
Особенно критичны:
- размер style.json
- количество
sources
- наличие custom fonts
- сетевые задержки тайлов
Инструментально измеряется через performance.mark:
performance.mark('map-start');
map.on('load', () => {
performance.mark('map-loaded');
performance.measure('map-ttfr', 'map-start', 'map-loaded');
});
Производительность тайловой
системы
Vector tiles — центральный элемент архитектуры.
Факторы влияния:
- размер тайла (gzip / pbf compression)
- количество геометрий
- сложность атрибутов
- zoom level density
- caching behavior
Узкие места:
- декодирование PBF в worker
- triangulation для fill layers
- simplification geometry
- sorting features by layer order
GPU и шейдерная нагрузка
WebGL-пайплайн Mapbox GL JS зависит от:
- количества draw calls
- сложности fragment shaders
- blending операций
- overdraw
Типичные проблемы:
- слишком много symbol layers → увеличение draw calls
- большие fill-extrusion сцены → высокая нагрузка на fragment
shader
- прозрачность слоёв → overdraw
Сложность стилей и слоёв
Количество слоёв напрямую влияет на производительность.
Критические факторы:
- symbol layers — самые дорогие
- layout properties — пересчитываются при каждом
zoom
- paint properties — влияют на GPU
- expressions — могут вычисляться на CPU
Особенно тяжелы:
"filter": ["all",
["has", "population"],
[">", ["get", "population"], 100000]
]
При увеличении количества фильтров стоимость рендера растёт
нелинейно.
Camera updates и
интерактивность
Операции:
влияют на:
- пересчёт матрицы камеры
- перерасчёт видимых тайлов
- перерисовку слоёв
Тестирование включает:
- continuous zoom stress
- rapid pan simulation
- inertia testing
Memory leak тестирование
Основные источники утечек:
- неосвобождённые sources
- accumulation event listeners
- cached tiles
- persistent WebGL buffers
Методика:
- длительный прогон (30–120 минут)
- фиксированный сценарий движения карты
- периодический snapshot heap
Инструменты профилирования
Используются:
- Chrome DevTools Performance tab
- WebGL inspector
- Mapbox telemetry hooks
performance.getEntries()
- memory snapshots
Типовой анализ:
- flame chart main thread
- worker activity breakdown
- GPU frame timing (через external tools)
Бенчмарки реальных сценариев
Городская карта
- 50k–200k POI
- clustering enabled
- 10–15 layers
Проблема:
Heatmap
- большие datasets
- aggregation on GPU
Проблема:
3D extrusion
- fill-extrusion layers
- high zoom levels
Проблема:
Оптимизационные
наблюдения, выявляемые тестами
- уменьшение symbol layers даёт наибольший прирост FPS
- clustering снижает CPU, но увеличивает preprocessing cost
- tile caching критичен для smooth pan
- simplification geometry улучшает TTFR
- снижение precision координат ускоряет render pipeline
Типовой pipeline:
- фиксированный dataset
- headless Chromium
- puppeteer сценарии
- сбор FPS / memory / TTFR
- сравнение с baseline
Пример структуры теста:
await page.goto('http://localhost:3000');
const metrics = await page.evaluate(() => {
return window.__MAP_METRICS__;
});
Интерпретация результатов
Важный аспект — не абсолютные значения, а деградация:
- +10% draw time при добавлении слоя
- рост memory usage после zoom cycles
- ухудшение 1% low FPS при clustering off
Показатели должны анализироваться в динамике между версиями и
конфигурациями стиля.