синхронизация фона рабочей области

Когда вы отправляете данные на веб-сервер, иногда запросы не выполняются. Это может быть связано с тем, что пользователь потерял соединение или сервер не работает; в любом случае вам часто захочется попробовать отправить запросы позже.

Новый API BackgroundSync — идеальное решение этой проблемы. Когда работник службы обнаруживает, что сетевой запрос не выполнен, он может зарегистрироваться для получения события sync , которое доставляется, когда браузер считает, что подключение восстановлено. Обратите внимание, что событие синхронизации может быть доставлено , даже если пользователь покинул приложение , что делает его намного более эффективным, чем традиционный метод повтора неудачных запросов.

Фоновая синхронизация Workbox предназначена для упрощения использования API BackgroundSync и интеграции его использования с другими модулями Workbox. Он также реализует запасной вариант для браузеров, которые еще не поддерживают BackgroundSync.

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

Основное использование

Самый простой способ использовать фоновую синхронизацию — использовать Plugin , который автоматически ставит в очередь неудачные запросы и повторяет их при возникновении будущих событий sync .

import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60, // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
  'POST'
);

BackgroundSyncPlugin подключается к обратному вызову плагина fetchDidFail , и fetchDidFail вызывается только в случае возникновения исключения, скорее всего, из-за сбоя сети. Это означает, что запросы не будут повторяться, если получен ответ со статусом ошибки 4xx или 5xx . Если вы хотите повторить все запросы, которые приводят, например, к статусу 5xx , вы можете сделать это, добавив плагин fetchDidSucceed в свою стратегию:

const statusPlugin = {
  fetchDidSucceed: ({response}) => {
    if (response.status >= 500) {
      // Throwing anything here will trigger fetchDidFail.
      throw new Error('Server error.');
    }
    // If it's not 5xx, use the response as-is.
    return response;
  },
};

// Add statusPlugin to the plugins array in your strategy.

Расширенное использование

Фоновая синхронизация Workbox также предоставляет класс Queue , экземпляр которого можно создавать и добавлять в него неудачные запросы. Неудачные запросы сохраняются в IndexedDB и повторяются, когда браузер считает, что соединение восстановлено (т. е. когда он получает событие синхронизации).

Создание очереди

Чтобы создать очередь фоновой синхронизации Workbox, вам необходимо создать ее с именем очереди (которое должно быть уникальным для вашего источника ):

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

const queue = new Queue('myQueueName');

Имя очереди используется как часть имени тега, который register() с помощью глобального SyncManager . Оно также используется в качестве имени хранилища объектов для базы данных IndexedDB.

Добавление запроса в очередь

Создав экземпляр очереди, вы можете добавлять в него неудачные запросы. Вы добавляете неудавшийся запрос, вызывая метод .pushRequest() . Например, следующий код перехватывает все неудачные запросы и добавляет их в очередь:

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

const queue = new Queue('myQueueName');

self.addEventListener('fetch', event => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

После добавления в очередь запрос автоматически повторяется, когда сервисный работник получает событие sync (что происходит, когда браузер считает, что подключение восстановлено). Браузеры, которые не поддерживают API BackgroundSync, будут повторять попытку очереди каждый раз при запуске сервисного работника. Для этого требуется, чтобы страница, управляющая сервисным работником, была запущена, поэтому она будет не такой эффективной.

Тестирование фоновой синхронизации Workbox

К сожалению, тестирование BackgroundSync несколько неинтуитивно и сложно по ряду причин.

Лучший способ протестировать вашу реализацию — сделать следующее:

  1. Загрузите страницу и зарегистрируйте своего сервисного работника.
  2. Выключите сеть вашего компьютера или веб-сервер.
    • НЕ ИСПОЛЬЗУЙТЕ CHROME DEVTOOLS ОФФЛАЙН. Флажок «Автономный режим» в DevTools влияет только на запросы со страницы. Запросы Service Worker будут продолжать обрабатываться.
  3. Отправляйте сетевые запросы, которые должны быть поставлены в очередь с помощью фоновой синхронизации Workbox.
    • Вы можете проверить, что запросы были поставлены в очередь, просмотрев Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
  4. Теперь включите сеть или веб-сервер.
  5. Вызовите событие ранней sync , перейдя в Chrome DevTools > Application > Service Workers , введя имя тега workbox-background-sync:<your queue name> где <your queue name> должно быть именем установленной вами очереди, а затем нажав кнопку «Синхронизировать».

    Пример кнопки синхронизации в Chrome DevTools

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

Типы

BackgroundSyncPlugin

Класс, реализующий обратный вызов жизненного цикла fetchDidFail . Это упрощает добавление неудачных запросов в очередь фоновой синхронизации.

Характеристики

Queue

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

Характеристики

  • конструктор

    пустота

    Создает экземпляр Queue с заданными параметрами.

    Функция constructor выглядит так:

    (name: string,options?: QueueOptions)=> {...}

    • имя

      нить

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

    • параметры

      QueueOptions необязательно

  • имя

    нить

  • получить все

    пустота

    Возвращает все записи, срок действия которых не истек (в соответствии с maxRetentionTime ). Все записи с истекшим сроком действия удаляются из очереди.

    Функция getAll выглядит так:

    ()=> {...}

    • возвращает

      Обещание<QueueEntry[]>

  • popRequest

    пустота

    Удаляет и возвращает последний запрос в очереди (вместе с его отметкой времени и метаданными). Возвращаемый объект принимает форму: {request, timestamp, metadata} .

    Функция popRequest выглядит так:

    ()=> {...}

    • возвращает

      Обещание<QueueEntry>

  • pushRequest

    пустота

    Сохраняет переданный запрос в IndexedDB (с его отметкой времени и всеми метаданными) в конце очереди.

    Функция pushRequest выглядит так:

    (entry: QueueEntry)=> {...}

    • вход

      ОчередьЗапись

    • возвращает

      Обещание<void>

  • регистрациясинхронизировать

    пустота

    Регистрирует событие синхронизации с уникальным для этого экземпляра тегом.

    Функция registerSync выглядит так:

    ()=> {...}

    • возвращает

      Обещание<void>

  • повторыЗапросы

    пустота

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

    Функция replayRequests выглядит так:

    ()=> {...}

    • возвращает

      Обещание<void>

  • сдвигЗапрос

    пустота

    Удаляет и возвращает первый запрос в очереди (вместе с его отметкой времени и метаданными). Возвращаемый объект принимает форму: {request, timestamp, metadata} .

    shiftRequest выглядит так:

    ()=> {...}

    • возвращает

      Обещание<QueueEntry>

  • размер

    пустота

    Возвращает количество записей, присутствующих в очереди. Обратите внимание, что записи с истекшим сроком действия (по maxRetentionTime ) также включены в этот счетчик.

    Функция size выглядит так:

    ()=> {...}

    • возвращает

      Обещание<число>

  • unshiftЗапрос

    пустота

    Сохраняет переданный запрос в IndexedDB (с его отметкой времени и всеми метаданными) в начале очереди.

    Функция unshiftRequest выглядит так:

    (entry: QueueEntry)=> {...}

    • вход

      ОчередьЗапись

    • возвращает

      Обещание<void>

QueueOptions

Характеристики

  • ForceSyncFallback

    логическое значение необязательно

  • Максретентионтиме

    номер необязательно

  • onSync

    OnSyncCallback необязательно

QueueStore

Класс для управления хранением запросов из очереди в IndexedDB, индексированных по имени очереди для облегчения доступа.

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

Характеристики

  • конструктор

    пустота

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

    Функция constructor выглядит так:

    (queueName: string)=> {...}

    • имяочереди

      нить

  • удалить запись

    пустота

    Удаляет запись для данного идентификатора.

    ВНИМАНИЕ: этот метод не гарантирует, что удаленная запись принадлежит этой очереди (т. е. соответствует queueName ). Но это ограничение приемлемо, поскольку этот класс не публикуется. Дополнительная проверка сделает этот метод медленнее, чем нужно.

    Функция deleteEntry выглядит так:

    (id: number)=> {...}

    • идентификатор

      число

    • возвращает

      Обещание<void>

  • получить все

    пустота

    Возвращает все записи в хранилище, соответствующие queueName .

    Функция getAll выглядит так:

    ()=> {...}

    • возвращает

      Обещание<QueueStoreEntry[]>

  • popEntry

    пустота

    Удаляет и возвращает последнюю запись в очереди, соответствующую queueName .

    Функция popEntry выглядит так:

    ()=> {...}

    • возвращает

      Обещание<QueueStoreEntry>

  • pushEntry

    пустота

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

    Функция pushEntry выглядит так:

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • вход

      НеопознанныйОчередьStoreEntry

    • возвращает

      Обещание<void>

  • сдвигВвод

    пустота

    Удаляет и возвращает первую запись в очереди, соответствующую queueName .

    shiftEntry выглядит так:

    ()=> {...}

    • возвращает

      Обещание<QueueStoreEntry>

  • размер

    пустота

    Возвращает количество записей в хранилище, соответствующих queueName .

    Функция size выглядит так:

    ()=> {...}

    • возвращает

      Обещание<число>

  • unshiftEntry

    пустота

    Добавьте запись первой в очереди.

    Функция unshiftEntry выглядит так:

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • вход

      НеопознанныйОчередьStoreEntry

    • возвращает

      Обещание<void>

StorableRequest

Класс, упрощающий сериализацию и десериализацию запросов, чтобы их можно было хранить в IndexedDB.

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

Характеристики

  • конструктор

    пустота

    Принимает объект данных запроса, который можно использовать для создания Request , но также можно хранить в IndexedDB.

    Функция constructor выглядит так:

    (requestData: RequestData)=> {...}

    • запрос данных

      ЗапросДанные

      Объект данных запроса, включающий url и все соответствующие свойства [requestInit] https://fetch.spec.whatwg.org/#requestinit .

  • клонировать

    пустота

    Создает и возвращает глубокую копию экземпляра.

    Функция clone выглядит так:

    ()=> {...}

  • для объекта

    пустота

    Возвращает глубокую копию объекта экземпляра _requestData .

    Функция toObject выглядит так:

    ()=> {...}

    • возвращает

      ЗапросДанные

  • запрашивать

    пустота

    Преобразует этот экземпляр в запрос.

    Функция toRequest выглядит так:

    ()=> {...}

    • возвращает

      Запрос

  • из запроса

    пустота

    Преобразует объект Request в простой объект, который можно структурировать, клонировать или преобразовать в строку JSON.

    Функция fromRequest выглядит так:

    (request: Request)=> {...}

    • запрос

      Запрос