Стратегии уведомления пользователя об обновлении

Библиотека Sw-precache создаёт сервис-воркеры, которые автоматически кэшируют ресурсы веб-приложения для оффлайн-доступа и ускоренной загрузки. Одной из важных задач при использовании сервис-воркеров является информирование пользователя о доступности новой версии приложения. Без уведомлений пользователи могут продолжать работать с устаревшими данными, что приводит к рассинхронизации и проблемам в интерфейсе.

Sw-precache не предоставляет встроенных UI-элементов для уведомлений, но даёт инструменты для отслеживания обновлений сервис-воркера и вызова кастомных обработчиков.


Детектирование новой версии сервис-воркера

Для отслеживания обновлений сервис-воркера используется событие updatefound у регистрационного объекта. Регистрация сервис-воркера выглядит следующим образом:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js').then(registration => {
    registration.onupdatefo und = () => {
      const installingWorker = registration.installing;
      installingWorker.onstatecha nge = () => {
        if (installingWorker.state === 'installed') {
          if (navigator.serviceWorker.controller) {
            // Новая версия доступна
            showUpdateNotification();
          }
        }
      };
    };
  }).catch(error => {
    console.error('Service Worker registration failed:', error);
  });
}

Ключевые моменты:

  • navigator.serviceWorker.controller указывает на активный воркер. Если он присутствует при событии installed, значит обновление загрузилось, но ещё не активировалось.
  • installingWorker.state проходит через состояния: installing, installed, activating, activated, redundant. Событие installed — основной сигнал для уведомления о новой версии.

Стратегии уведомления пользователя

Мгновенное применение обновления

Можно автоматически активировать новую версию сервис-воркера и перезагрузить страницу:

function showUpdateNotification() {
  navigator.serviceWorker.getRegistration().then(reg => {
    if (reg.waiting) {
      reg.waiting.postMessage({ action: 'skipWaiting' });
    }
  });
  window.location.reload();
}
  • Плюсы: пользователи сразу работают с актуальной версией.
  • Минусы: внезапная перезагрузка может прервать текущие действия пользователя, потеряться несохранённые данные.

Уведомление с согласия пользователя

Более безопасная стратегия — показать баннер или диалог с предложением обновить приложение:

function showUpdateNotification() {
  const updateBanner = document.createElement('div');
  updateBanner.textContent = 'Доступна новая версия приложения. Обновить сейчас?';
  const updateButton = document.createElement('button');
  updateButton.textContent = 'Обновить';
  updateButton.oncl ick = () => {
    navigator.serviceWorker.getRegistration().then(reg => {
      if (reg.waiting) {
        reg.waiting.postMessage({ action: 'skipWaiting' });
      }
    });
    window.location.reload();
  };
  updateBanner.appendChild(updateButton);
  document.body.appendChild(updateBanner);
}
  • Позволяет пользователю завершить текущие задачи.
  • Минимизирует риск потери данных.
  • Подходит для приложений с интенсивным взаимодействием (редакторы, формы, игры).

Обработка сообщений от сервис-воркера

Sw-precache позволяет передавать сообщения между воркером и основной страницей. В сервис-воркере можно добавить обработчик для команды skipWaiting:

self.addEventListener('message', event => {
  if (event.data.action === 'skipWaiting') {
    self.skipWaiting();
  }
});
  • Сообщения позволяют синхронизировать состояние приложения с новым воркером.
  • Использование skipWaiting гарантирует немедленную активацию обновлённого воркера без ожидания закрытия всех вкладок.

Стратегия с постепенным обновлением

Для минимизации риска неожиданной перезагрузки можно реализовать подход “soft update”:

  1. Сохранять информацию о новой версии в localStorage или IndexedDB.
  2. Предлагать пользователю обновиться при следующем удобном действии (например, при следующей загрузке страницы или переходе по маршруту).
  3. При активации новой версии синхронизировать данные с сервером и только потом перезагружать страницу.
function scheduleUpdateNotification() {
  navigator.serviceWorker.getRegistration().then(reg => {
    if (reg.waiting) {
      localStorage.setItem('updateReady', 'true');
    }
  });
}

window.addEventListener('load', () => {
  if (localStorage.getItem('updateReady') === 'true') {
    showUpdateNotification();
    localStorage.removeItem('updateReady');
  }
});
  • Позволяет мягко интегрировать обновления, не нарушая пользовательский опыт.
  • Особенно полезно для сложных одностраничных приложений (SPA), где внезапная перезагрузка нежелательна.

Обновление кэша и контроль версий

Sw-precache генерирует манифест кэша с файлами, каждая версия воркера сопровождается уникальным хэшем. Это позволяет:

  • Проверять изменения в ресурсах автоматически.
  • Гарантировать, что новая версия приложения всегда будет доставлена пользователю после активации воркера.
  • Избежать конфликтов кэширования старых и новых ресурсов.
// Пример конфигурации sw-precache
swPrecache.write('service-worker.js', {
  staticFileGlobs: [
    'index.html',
    'scripts/**/*.js',
    'styles/**/*.css',
    'images/**/*.{png,jpg,gif}'
  ],
  stripPrefix: 'dist/',
  runtimeCaching: [{
    urlPattern: /\/api\/.*$/,
    handler: 'networkFirst'
  }]
});
  • staticFileGlobs — список файлов для предзагрузки.
  • runtimeCaching — стратегия для динамических ресурсов.

Объединение этих возможностей с механизмами уведомлений обеспечивает надёжное и контролируемое обновление веб-приложения.


Практические рекомендации

  • Для SPA важно проверять наличие новой версии при каждом переходе по маршруту.
  • Баннер уведомления должен быть заметным, но не мешать основному интерфейсу.
  • В сложных приложениях стоит хранить состояние обновления в хранилище (localStorage/IndexedDB) для контроля процесса.
  • Всегда учитывать, что сервис-воркер может обновиться, пока вкладка активна, поэтому обработка updatefound и statechange должна быть стабильной и отлаженной.

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