Профилирование представляет собой процесс анализа производительности приложения, построенного на базе Kepler.gl, с целью выявления узких мест, избыточных вычислений, проблем визуализации и неоптимального использования памяти. Поскольку библиотека предназначена для отображения больших геопространственных наборов данных, производительность напрямую влияет на пользовательский опыт.
При работе с десятками тысяч объектов нагрузка распределяется между несколькими компонентами:
Профилирование позволяет определить, какой из этих уровней становится источником деградации производительности.
В контексте Kepler.gl обычно анализируются несколько категорий производительности.
Характеризует время между началом импорта и появлением слоя на карте.
На скорость загрузки влияют:
Пример проблемного сценария:
dispatch(
addDataToMap({
datasets: {
info: {
label: 'Large Dataset'
},
data: hugeGeoJson
}
})
);
Если hugeGeoJson содержит сотни тысяч объектов, загрузка
может занимать несколько секунд.
Связана с количеством объектов, которые должны быть визуализированы через Deck.gl.
Критические факторы:
Например:
{
type: 'geojson',
config: {
dataId: 'cities',
isVisible: true
}
}
Если слой содержит сложные полигоны административных границ, нагрузка на GPU возрастает многократно.
Оценивает скорость отклика интерфейса.
Проверяются:
Даже если карта загружается быстро, задержки при масштабировании свидетельствуют о проблемах рендеринга.
Важна при длительной работе приложения.
Признаки проблем:
Наиболее распространённый инструмент анализа производительности.
Основные вкладки:
Открытие:
F12 → Performance
Позволяет записывать полную временную диаграмму выполнения приложения.
Используется для анализа React-компонентов.
Особенно полезен при интеграции Kepler.gl в собственные приложения.
Установка:
Chrome Web Store → React Developer Tools
После установки появляется вкладка:
Profiler
Она показывает:
Поскольку Kepler.gl активно использует Redux, значительная часть производительности зависит от действий и изменений состояния.
Инструмент позволяет отслеживать:
{
type: '@@kepler.gl/LAYER_CONFIG_CHANGE'
}
или
{
type: '@@kepler.gl/SET_FILTER'
}
С помощью журнала действий можно определить операции, вызывающие избыточные обновления.
При работе с тяжёлыми слоями полезен анализ WebGL-вызовов.
Проверяются:
Простейший способ анализа — использование API производительности браузера.
performance.mark('load-start');
dispatch(addDataToMap(config));
performance.mark('load-end');
performance.measure(
'dataset-load',
'load-start',
'load-end'
);
Получение результата:
console.log(
performance.getEntriesByName('dataset-load')
);
При загрузке GeoJSON часто именно парсинг становится самым затратным этапом.
Пример:
const data = JSON.parse(rawJson);
Для файлов размером более 100 МБ время выполнения может измеряться секундами.
Профилирование позволяет определить:
performance.mark('parse-start');
const dataset = JSON.parse(content);
performance.mark('parse-end');
performance.measure(
'parsing',
'parse-start',
'parse-end'
);
Полученные данные отображаются в Chrome DevTools.
Частая проблема заключается в повторных рендерах компонентов при отсутствии изменений данных.
Пример:
function MapContainer(props) {
return <KeplerGl id="map" />;
}
Если родительский компонент обновляется слишком часто, карта может перерисовываться без необходимости.
Оптимизация:
const MapContainer = React.memo(function MapContainer() {
return <KeplerGl id="map" />;
});
После применения профайлер показывает снижение количества рендеров.
React Profiler предоставляет показатель:
Commit Duration
Он показывает время, затраченное на применение изменений к DOM.
Большие значения обычно свидетельствуют о:
Иногда одно действие запускает целый каскад обновлений.
Например:
dispatch(updateVisData(data));
может привести к:
UPDATE_VIS_DATA
LAYER_CONFIG_CHANGE
VIS_STATE_UPDATE
TRIGGER_RENDER
Каждое обновление увеличивает нагрузку.
Middleware позволяет регистрировать длительность операций.
const profiler = store => next => action => {
const start = performance.now();
const result = next(action);
const end = performance.now();
console.log(
action.type,
end - start
);
return result;
};
Такой подход помогает обнаруживать дорогостоящие операции.
Kepler.gl строится поверх Deck.gl.
Основная нагрузка возникает именно здесь:
Redux
↓
Kepler.gl
↓
Deck.gl
↓
WebGL
Поэтому анализ Deck.gl имеет критическое значение.
Включение детального вывода:
import {log} from '@deck.gl/core';
log.enable();
Логи содержат информацию о:
new ScatterplotLayer({
id: 'points',
data,
updateTriggers: {
getRadius: radius
}
});
Если значение radius изменяется слишком часто, слой
будет пересчитываться многократно.
Профилирование позволяет обнаружить подобные ситуации.
При работе с интерактивной картой важно поддерживать стабильную частоту кадров.
Целевые показатели:
| FPS | Состояние |
|---|---|
| 60 | Отлично |
| 45–60 | Хорошо |
| 30–45 | Допустимо |
| Менее 30 | Проблема |
Пример использования библиотеки stats.js:
import Stats from 'stats.js';
const stats = new Stats();
document.body.appendChild(stats.dom);
function animate() {
stats.begin();
requestAnimationFrame(animate);
stats.end();
}
animate();
Позволяет наблюдать производительность в реальном времени.
Вкладка Memory в Chrome позволяет создавать снимки памяти.
Этапы анализа:
Проверяется наличие объектов, которые должны были быть удалены.
Пример потенциальной утечки:
const cache = [];
function saveData(dataset) {
cache.push(dataset);
}
Если данные никогда не удаляются, потребление памяти будет постоянно расти.
Распространённая ошибка:
window.addEventListener(
'resize',
onResize
);
Без удаления:
window.removeEventListener(
'resize',
onResize
);
Обработчики продолжают существовать после уничтожения компонентов.
Перед загрузкой полезно определить характеристики набора данных.
Пример:
console.log(
geojson.features.length
);
Дополнительно анализируется количество координат.
let vertices = 0;
geojson.features.forEach(feature => {
vertices += feature.geometry.coordinates.length;
});
Чем больше вершин, тем выше нагрузка на GPU.
Высокодетализированные полигоны часто становятся причиной снижения производительности.
До оптимизации:
1 000 000 вершин
После применения алгоритмов упрощения:
50 000 вершин
Время рендеринга может сократиться в десятки раз.
Большие наборы точек выгодно агрегировать.
Вместо:
500 000 объектов
можно отображать:
5 000 кластеров
Нагрузка на видеокарту значительно снижается.
Каждое изменение фильтра инициирует перерасчёт данных.
Пример:
dispatch(
setFilter({
value: [100, 500]
})
);
При больших объёмах данных операция может занимать заметное время.
const start = performance.now();
dispatch(updateFilter(filter));
const end = performance.now();
console.log(end - start);
Результаты позволяют определить предельные объёмы данных для выбранного типа фильтра.
Анимированные карты требуют особого внимания к производительности.
Основные источники нагрузки:
В Chrome Performance можно определить:
Критическим считается кадр длительностью более:
16.6 мс
поскольку это препятствует достижению 60 FPS.
Признаки:
Типичные причины:
Признаки:
Причины:
Признаки:
Причины:
Определяется конкретный симптом:
Медленная загрузка
Низкий FPS
Зависания интерфейса
Рост памяти
Используется Chrome Performance.
Запись должна охватывать полный сценарий:
Загрузка данных
Масштабирование
Перемещение карты
Фильтрация
Анализируются:
Возможные меры:
После каждого изменения выполняется новое профилирование.
Сравниваются показатели:
| Метрика | До | После |
|---|---|---|
| Время загрузки | 4.8 с | 1.2 с |
| FPS | 24 | 58 |
| Память | 1.3 ГБ | 420 МБ |
| Время фильтрации | 650 мс | 70 мс |
Только повторные измерения позволяют объективно оценить эффективность оптимизации и подтвердить улучшение производительности приложения на базе Kepler.gl.