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

Основные концепции

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

Ключевой объект для этого — Background Sync. Он позволяет помещать запросы в очередь, если сеть недоступна, и автоматически повторно отправлять их при восстановлении соединения. Workbox предоставляет абстракцию workbox.backgroundSync.Queue, которая упрощает управление такими очередями.

Создание очереди действий

Для создания очереди достаточно импортировать соответствующий модуль и создать экземпляр:

import { Queue } from 'workbox-background-sync';

const userActionsQueue = new Queue('userActionsQueue', {
  maxRetentionTime: 24 * 60 // время хранения элементов в очереди в минутах
});

Ключевые параметры:

  • name — уникальное имя очереди, по которому Workbox хранит данные в IndexedDB.
  • maxRetentionTime — максимальное время хранения элементов в очереди. После его истечения элемент удаляется, даже если не удалось отправить запрос на сервер.

Добавление действий в очередь

Когда пользователь выполняет действие, требующее сетевого запроса, необходимо проверять доступность сети и при необходимости помещать запрос в очередь:

async function sendUserAction(request) {
  try {
    const response = await fetch(request);
    if (!response.ok) throw new Error('Network error');
    return response;
  } catch (error) {
    await userActionsQueue.pushRequest({ request });
    console.log('Действие добавлено в очередь для последующей отправки');
  }
}

pushRequest принимает объект с полем request, которое может быть экземпляром Request или объектом, совместимым с fetch. Все добавленные элементы сохраняются в IndexedDB и автоматически отправляются, когда сеть станет доступной.

Настройка повторной отправки

Workbox позволяет управлять стратегией повторной отправки. Очередь может использовать обработчик onSync, который вызывается при срабатывании Background Sync:

const queue = new Queue('userActionsQueue', {
  onSync: async ({ queue }) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        await fetch(entry.request);
        console.log('Действие успешно отправлено');
      } catch (err) {
        console.error('Не удалось отправить действие, возвращаем в очередь', err);
        await queue.unshiftRequest(entry);
        break;
      }
    }
  }
});

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

  • shiftRequest() извлекает следующий элемент из очереди.
  • В случае неудачной отправки элемент можно вернуть в начало очереди через unshiftRequest().
  • Цикл while позволяет обрабатывать все элементы очереди по мере их доступности.

Интеграция с Service Worker

Очередь пользовательских действий работает внутри Service Worker. Для интеграции достаточно зарегистрировать обработчик fetch, который будет направлять запросы в очередь при недоступной сети:

self.addEventListener('fetch', (event) => {
  const request = event.request;

  if (request.method === 'POST' && request.url.includes('/api/user-action')) {
    event.respondWith(
      (async () => {
        try {
          return await fetch(request);
        } catch (error) {
          await userActionsQueue.pushRequest({ request });
          return new Response(JSON.stringify({ status: 'queued' }), {
            headers: { 'Content-Type': 'application/json' }
          });
        }
      })()
    );
  }
});

Таким образом, любое действие пользователя, требующее POST-запроса, автоматически добавляется в очередь при отсутствии сети, а клиент получает подтверждение о сохранении действия для последующей отправки.

Очередь и порядок выполнения действий

Workbox гарантирует сохранение порядка добавления элементов. Это особенно важно для сценариев, где порядок операций критичен, например, при обновлении состояния объекта на сервере. Все элементы очереди выполняются последовательно, и только после успешного завершения одного запроса выполняется следующий.

Очистка и управление очередями

Workbox предоставляет методы для управления очередями:

  • queue.getAll() — получить все элементы в очереди.
  • queue.deleteEntry(entry) — удалить конкретный элемент.
  • queue.replayRequests() — повторно отправить все элементы, даже если Background Sync не сработал автоматически.

Дополнительные возможности

  1. Фильтрация и маршрутизация: Можно создавать несколько очередей для разных типов действий (например, лайки, комментарии, формы) и управлять ими отдельно.
  2. Поддержка продвинутых стратегий retry: Workbox позволяет интегрировать exponential backoff для повторных попыток отправки запросов.
  3. Интеграция с IndexedDB: Все данные очереди сохраняются локально, что обеспечивает сохранность даже при перезапуске браузера.

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

  • Всегда использовать maxRetentionTime, чтобы очередь не разрасталась бесконтрольно.
  • Обрабатывать ошибки на уровне onSync, чтобы избежать застревания элементов в очереди.
  • Разделять очереди по типу действий для упрощения отладки и мониторинга.
  • В критичных сценариях можно уведомлять пользователя о статусе действий, чтобы обеспечить прозрачность работы офлайн-функциональности.

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