Визуализация больших геопространственных наборов данных требует разделения ответственности между основным потоком браузера и фоновыми вычислениями. В Kepler.gl вычислительная нагрузка, связанная с парсингом данных, агрегацией, индексацией и подготовкой слоёв визуализации, вынесена в Web Workers, что позволяет сохранить отзывчивость интерфейса даже при работе с миллионами строк.
Kepler.gl строится на принципе разделения pipeline на две части: UI-слой (React + Redux + deck.gl) и вычислительный слой (worker threads). Основная идея заключается в том, что тяжёлые операции никогда не блокируют главный поток, а выполняются в изолированной среде с последующей передачей результата обратно.
JavaScript в браузере работает в одном потоке исполнения, и любые синхронные вычисления приводят к блокировке отрисовки интерфейса. При обработке геоданных это становится критичным из-за следующих факторов:
Web Workers решают проблему за счёт:
В Kepler.gl обработка данных проходит через несколько этапов:
Каждый этап реализован как чистая функция без побочных эффектов, что позволяет эффективно кэшировать и переиспользовать результаты.
Worker в Kepler.gl реализует набор функций обработки, которые вызываются через сообщения. Основные задачи worker-а:
Передача данных осуществляется через postMessage, где
payload строго сериализуется.
Пример концептуальной структуры сообщения:
worker.postMessage({
type: 'PROCESS_FILE',
payload: {
data: rawData,
options: {
format: 'csv',
delimiter: ','
}
}
});
Web Worker не имеет доступа к DOM, window и глобальному состоянию интерфейса. Это накладывает архитектурные ограничения:
С другой стороны, это даёт важное преимущество — отсутствие конкуренции за главный поток выполнения.
Одной из ключевых проблем при работе с Web Workers является стоимость копирования данных. При передаче больших массивов возникает значительная нагрузка на память и CPU.
Для оптимизации используются:
Буферы ArrayBuffer передаются без копирования:
worker.postMessage({
buffer: arrayBuffer
}, [arrayBuffer]);
После передачи оригинальный буфер становится недоступным в основном потоке.
Для сложных объектов используется structured clone algorithm, однако он менее эффективен и применяется только там, где невозможно использовать transfer.
Обработка входных данных — один из самых тяжёлых этапов pipeline. В Kepler.gl используются оптимизированные парсеры:
Парсинг CSV часто реализуется построчно, что позволяет избежать загрузки всего файла в память:
function parseCSVStream(chunk) {
const rows = chunk.split('\n');
for (let i = 0; i < rows.length; i++) {
processRow(rows[i]);
}
}
Внутренняя модель Kepler.gl основана на таблицах, где каждая колонка хранится отдельно. Это позволяет:
Worker преобразует входные данные в columnar storage:
{
columns: {
latitude: Float32Array,
longitude: Float32Array,
timestamp: Int32Array
}
}
Такой формат оптимизирован для GPU-пайплайна deck.gl.
Для работы с большими наборами геоданных используется пространственная индексация:
Индексация выполняется в worker, так как требует значительных вычислений.
Пример логики:
function buildSpatialIndex(points) {
const index = new Map();
for (const p of points) {
const cell = h3.latLngToCell(p.lat, p.lng, 7);
if (!index.has(cell)) index.set(cell, []);
index.get(cell).push(p);
}
return index;
}
При работе с временными данными worker выполняет:
Такая агрегация снижает объём данных для визуализации и ускоряет рендеринг.
Результаты работы worker возвращаются в основной поток и интегрируются в глобальное состояние через Redux.
Схема взаимодействия:
Такой подход обеспечивает предсказуемость состояния и упрощает отладку.
Worker не может выбрасывать исключения напрямую в основной поток, поэтому ошибки сериализуются:
self.postMessage({
type: 'ERROR',
error: {
message: err.message,
stack: err.stack
}
});
Основной поток интерпретирует сообщение и обновляет UI состояния ошибки.
Основные факторы, влияющие на производительность:
Оптимизации включают:
Для очень больших файлов применяется потоковая модель:
Это позволяет работать с файлами, превышающими доступную память.
Результаты worker-обработки передаются в deck.gl слои, которые используют WebGL для рендеринга. Подготовленные данные уже находятся в оптимизированной форме:
Это снижает нагрузку на GPU и CPU во время отрисовки.
Worker-архитектура позволяет масштабировать обработку данных:
В результате достигается устойчивость при работе с миллионами записей без деградации интерфейса.