Pre-downloading tiles

В веб-картах на базе Mapbox GL JS производительность во многом определяется тем, насколько заранее загружены тайлы, спрайты и шрифты. Поведение загрузки в этой библиотеке ленивое: данные подгружаются по мере приближения камеры к соответствующим координатам и зумам. Это снижает начальный трафик, но может приводить к «пустым» областям при резких перемещениях карты. Управление предварительной загрузкой тайлов становится ключевым инструментом оптимизации UX.


Внутренняя логика загрузки в Mapbox GL JS основана на:

  • текущем центре карты
  • уровне масштаба (zoom)
  • viewport (размере экрана)
  • padding (отступах вокруг экрана)
  • tile pyramid (пирамиде тайлов)

Каждое движение камеры инициирует перерасчёт видимых тайлов. Однако библиотека также использует prefetch-зону — расширенную область вокруг viewport, где тайлы загружаются заранее.


Prefetch zoom delta

Основной механизм предварительной загрузки тайлов — параметр prefetchZoomDelta.

Он определяет, на сколько уровней масштабирования «вперёд» будут подгружаться тайлы.

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12',
  center: [69.2401, 41.2995],
  zoom: 10,
  prefetchZoomDelta: 3
});

Поведение параметра

  • значение 0 — подгружается только текущий zoom
  • 1–2 — умеренное предзагружение (баланс)
  • 3–4 — агрессивная предзагрузка
  • высокие значения увеличивают сетевой трафик и память

При увеличении zoom пользователю кажется, что карта «мгновенно» отрисовывается, поскольку тайлы уже находятся в кеше.


Кэш тайлов и управление памятью

Mapbox GL JS хранит тайлы в памяти, используя внутренний LRU-кэш.

Ключевые факторы:

  • количество тайлов зависит от viewport
  • увеличивается при высоких zoom уровнях
  • ограничено браузером и внутренними лимитами WebGL

Ограничение кэша

map.addControl(new mapboxgl.NavigationControl());

map.setMaxTileCacheSize && map.setMaxTileCacheSize(200); 

В некоторых версиях управление размером кэша реализовано косвенно через параметры производительности и ограничение области отображения.


Ограничение области загрузки

Сильное влияние на предзагрузку оказывает ограничение географии карты.

map.setMaxBounds([
  [68.0, 40.0],
  [71.0, 42.5]
]);

Эффект:

  • тайлы вне bounds не запрашиваются
  • уменьшается количество предзагружаемых данных
  • повышается предсказуемость кэша

Это особенно важно для специализированных приложений (логистика, городские сервисы).


Управление жизненным циклом тайлов

Событие idle

Одним из ключевых инструментов является событие idle, сигнализирующее, что:

  • нет текущих запросов тайлов
  • нет анимаций
  • карта стабилизировалась
map.on('idle', () => {
  console.log('карта полностью загружена');
});

Это событие часто используется для запуска дополнительных стратегий предзагрузки.


Программная «прогрузка» тайлов

Хотя библиотека не предоставляет прямого API preloadTiles, эффект можно добиться искусственно изменяя состояние камеры.

Стратегия ступенчатого зума

async function warmUp(map) {
  const startZoom = map.getZoom();

  for (let z = startZoom; z <= startZoom + 2; z += 0.5) {
    map.easeTo({ zoom: z, duration: 0 });
    await new Promise(r => setTimeout(r, 50));
  }

  map.easeTo({ zoom: startZoom, duration: 0 });
}

Поведение:

  • инициируется загрузка тайлов на соседних zoom уровнях
  • кэш заполняется заранее
  • последующие взаимодействия становятся плавнее

Предзагрузка при перемещении камеры

При работе с анимациями (flyTo, easeTo) полезно заранее загружать тайлы целевой области.

map.flyTo({
  center: [69.5, 41.3],
  zoom: 12,
  essential: true
});

Чтобы усилить эффект предзагрузки, применяют «двойной проход»:

  1. быстрое перемещение без анимации
  2. возврат к нормальной позиции
map.jumpTo({ center: target, zoom: 12 });
map.jumpTo({ center: start, zoom: 10 });
map.flyTo({ center: target, zoom: 12 });

Prefetch через скрытую карту

Один из наиболее стабильных методов — создание второго экземпляра карты.

const preloadMap = new mapboxgl.Map({
  container: document.createElement('div'),
  style: 'mapbox://styles/mapbox/streets-v12',
  center: [69.2401, 41.2995],
  zoom: 12,
  interactive: false,
  prefetchZoomDelta: 4
});

Особенности:

  • карта не рендерится пользователю
  • тайлы загружаются в общий кэш
  • основная карта использует уже готовые данные

Этот подход эффективен для SPA-приложений.


Предзагрузка ресурсов стиля

Тайлы — не единственный источник задержек. Стиль карты включает:

  • sprite (иконки)
  • glyphs (шрифты)
  • JSON-стиль

Контроль загрузки через transformRequest

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12',
  transformRequest: (url, resourceType) => {
    return {
      url,
      headers: {
        'x-preload': '1'
      }
    };
  }
});

Это позволяет:

  • управлять кешированием на CDN уровне
  • добавлять заголовки для прогрева кеша
  • логировать предварительные загрузки

Работа с сетевым кешем браузера

Даже при оптимальной настройке Mapbox GL JS критично поведение HTTP-кеша:

  • Cache-Control: max-age
  • ETag
  • CDN edge caching

Тайлы, спрайты и glyphs повторно используются между сессиями, если сервер настроен корректно.


Баланс между производительностью и трафиком

Предзагрузка всегда является компромиссом:

Агрессивная стратегия

  • высокий prefetchZoomDelta
  • скрытая карта-прогрев
  • расширенные bounds

Плюсы:

  • минимальные задержки рендеринга

Минусы:

  • высокий трафик
  • рост потребления памяти

Умеренная стратегия

  • prefetchZoomDelta 1–2
  • ограниченные bounds
  • отсутствие скрытой карты

Плюсы:

  • стабильная работа
  • экономия ресурсов

Минусы:

  • возможные задержки при резких перемещениях

Поведение при быстрых перемещениях

При частом pan/zoom библиотека:

  • отменяет старые запросы тайлов
  • приоритизирует ближайшие tiles
  • использует дедупликацию запросов

Однако при слабом интернете может возникать эффект «размытого прогрева», когда низкоуровневые тайлы остаются дольше.


Влияние WebGL контекста

Предзагрузка тайлов тесно связана с:

  • количеством активных текстур
  • состоянием WebGL контекста
  • GPU памятью

При переполнении кэша:

  • старые тайлы выгружаются
  • повторные запросы инициируются заново

Это важно учитывать при больших zoom (>14) и высоких разрешениях экранов.


Практика оптимизации холодного старта

Типичная стратегия ускорения первой отрисовки:

  • установка центра и zoom до создания карты (если известны)
  • prefetchZoomDelta ≥ 2
  • ограничение bounds
  • использование скрытой карты для прогрева
  • минимизация тяжёлых слоёв на первом стиле

Типичные ошибки при предзагрузке

  • установка слишком высокого prefetchZoomDelta без анализа трафика
  • отсутствие ограничения bounds в глобальных картах
  • попытка «жёстко» контролировать тайлы через внешние циклы
  • игнорирование glyphs и sprite ресурсов
  • создание множества карт без повторного использования кэша

Эти ошибки приводят к нестабильному потреблению памяти и деградации производительности вместо её улучшения