Обработка отсутствия интернета

Работа с Google Maps JavaScript API предполагает постоянное взаимодействие с удалёнными серверами: загрузка скрипта API, тайлов карты, геокодирование, маршрутизация и поиск мест выполняются через сеть. Поэтому первым уровнем устойчивости становится определение состояния подключения браузера.

Используются встроенные механизмы браузера:

const isOnline = navigator.onLine;

и события изменения состояния сети:

window.addEventListener('online', () => {
  console.log('Соединение восстановлено');
});

window.addEventListener('offline', () => {
  console.log('Интернет отсутствует');
});

Эти события не гарантируют точного состояния соединения с интернетом (например, Wi-Fi может быть подключён без доступа к сети), однако они дают базовый сигнал для переключения режима работы интерфейса.


Контроль загрузки Google Maps API и обработка ошибок инициализации

Google Maps JavaScript API подключается через <script>-тег, и его загрузка может завершиться неудачей при отсутствии сети или блокировке запросов.

Критически важно обрабатывать onerror:

<script
  src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=initMap"
  async
  defer
  oner ror="handleMapLoadError()">
</script>
function handleMapLoadError() {
  console.error('Не удалось загрузить Google Maps API');

  showFallbackUI({
    title: 'Карта недоступна',
    message: 'Отсутствует подключение к интернету или сервер API недоступен'
  });
}

При такой ошибке объект google.maps не будет определён, поэтому любые обращения к нему должны выполняться только после проверки:

if (!window.google || !window.google.maps) {
  // запрет работы с картой
}

Отказоустойчивый запуск карты

Инициализация карты должна учитывать возможное отсутствие сетевых ресурсов уже на этапе создания объекта:

let map;

function initMap() {
  if (!navigator.onLine) {
    renderOfflineState();
    return;
  }

  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 51.1694, lng: 71.4491 },
    zoom: 10
  });
}

Если соединение пропадает после инициализации, карта продолжает отображаться, но новые тайлы и данные перестают загружаться.


Поведение карты при потере соединения во время работы

Google Maps JavaScript API не выбрасывает явную ошибку при обрыве сети после загрузки. Вместо этого наблюдаются следующие эффекты:

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

Обработка таких ситуаций выполняется через проверку статусов ответов сервисов API:

const geocoder = new google.maps.Geocoder();

geocoder.geocode({ address: "Astana" }, (results, status) => {
  if (status === "OK") {
    console.log(results);
  } else {
    console.error("Ошибка геокодирования:", status);
  }
});

Типичные статусы при проблемах с сетью:

  • UNKNOWN_ERROR
  • REQUEST_DENIED
  • OVER_QUERY_LIMIT
  • ZERO_RESULTS (не всегда связано с сетью)

Реакция на потерю соединения в пользовательском интерфейсе

Интерфейс должен разделять три состояния:

  1. Полная работоспособность карты
  2. Частичная деградация (карта видна, сервисы недоступны)
  3. Полная недоступность API

Пример переключения состояния:

function updateConnectionState() {
  if (!navigator.onLine) {
    setUIState('offline');
  } else if (!window.google?.maps) {
    setUIState('api-unavailable');
  } else {
    setUIState('online');
  }
}

Очередь запросов и повтор при восстановлении сети

Запросы к сервисам (геокодирование, маршруты, Places API) можно ставить в очередь при отсутствии сети.

const requestQueue = [];

function enqueueRequest(fn) {
  requestQueue.push(fn);
}

window.addEventListener('online', () => {
  while (requestQueue.length) {
    const req = requestQueue.shift();
    req();
  }
});

Пример использования:

function safeGeocode(address) {
  if (!navigator.onLine) {
    enqueueRequest(() => safeGeocode(address));
    return;
  }

  geocoder.geocode({ address }, callback);
}

Такой подход предотвращает потерю пользовательских действий в офлайн-сценариях.


Использование Service Worker для кэширования ресурсов

Service Worker позволяет частично компенсировать отсутствие сети за счёт кэширования статических ресурсов приложения.

Базовая регистрация:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

Внутри sw.js можно кэшировать собственные ресурсы интерфейса:

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('app-cache').then((cache) => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/app.js'
      ]);
    })
  );
});

Важно учитывать ограничение: динамические ресурсы Google Maps (тайлы карты, данные Places, маршруты) не предназначены для полноценного офлайн-кэширования через Service Worker в большинстве сценариев использования API и могут иметь ограничения со стороны платформы и условий сервиса.


Fallback-режим отображения карты

При отсутствии сети интерфейс может переключаться на альтернативное представление:

  • статичное изображение последней известной позиции;
  • список сохранённых объектов;
  • координаты без визуальной карты;
  • заглушка с сохранённым снимком.

Пример переключения контейнера:

function renderOfflineState() {
  const mapContainer = document.getElementById("map");

  mapContainer.innerHTML = `
    <div class="offline-map">
      <p>Карта недоступна</p>
    </div>
  `;
}

Обработка ошибок загрузки тайлов и API-запросов

При частичной потере соединения тайлы могут не загружаться, оставляя серые блоки. Контроль таких ситуаций выполняется косвенно через события и наблюдение за состоянием DOM.

Дополнительно можно отслеживать ошибки API через глобальный обработчик:

window.gm_authFailure = function () {
  console.error("Ошибка авторизации Google Maps API");
};

Повторные попытки загрузки и экспоненциальная задержка

Для устойчивости к нестабильной сети используется стратегия повторных попыток:

async function retry(fn, attempts = 5, delay = 1000) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (e) {
      await new Promise(r => setTimeout(r, delay * 2 ** i));
    }
  }
  throw new Error("Все попытки завершились неудачей");
}

Этот подход особенно полезен для геокодирования и запросов маршрутов.


Диагностика состояния сети и качества соединения

Дополнительно используется Network Information API:

const connection = navigator.connection;

if (connection) {
  console.log(connection.effectiveType);
}

Значения:

  • slow-2g
  • 2g
  • 3g
  • 4g

Это позволяет заранее снижать частоту запросов и отключать тяжёлые функции.


Разделение критических и некритических функций карты

При отсутствии интернета система должна различать:

Критические зависимости:

  • загрузка Google Maps API
  • тайлы карты
  • геокодирование

Некритические функции:

  • UI-анимации
  • локальные маркеры
  • сохранённые данные пользователя
  • локальные вычисления

Такая сегментация позволяет сохранить работоспособность интерфейса даже при полной деградации сети.


Предзагрузка и кэширование состояния карты

В некоторых сценариях полезно сохранять состояние карты:

function saveMapState(map) {
  const center = map.getCenter();
  const zoom = map.getZoom();

  localStorage.setItem('mapState', JSON.stringify({
    lat: center.lat(),
    lng: center.lng(),
    zoom
  }));
}

При восстановлении соединения это состояние используется для возврата пользователя к последнему просмотру.


Управление пользовательскими ошибками сервисов Places и Directions

Запросы к сервисам маршрутизации требуют отдельной обработки:

directionsService.route(request, (result, status) => {
  if (status === "OK") {
    directionsRenderer.setDirections(result);
  } else {
    console.error("Ошибка маршрута:", status);
    showOfflineRouteHint();
  }
});

При отсутствии сети такие запросы чаще всего возвращают UNKNOWN_ERROR, что требует унифицированной обработки без привязки к конкретному сервису.


Ограничения офлайн-работы Google Maps JavaScript API

Полноценная офлайн-работа невозможна из-за архитектуры API:

  • карта зависит от динамических тайлов;
  • данные Places не локальны;
  • маршрутизация выполняется на сервере;
  • лицензия ограничивает кэширование геоданных.

Поэтому офлайн-стратегии сводятся к:

  • сохранению состояния интерфейса;
  • очередям запросов;
  • fallback-отображению;
  • минимальному локальному функционалу без API.