В 2015 году мы представили фоновую синхронизацию , которая позволяет сервисному работнику откладывать работу до тех пор, пока у пользователя не будет подключения. Это означает, что пользователь может ввести сообщение, нажать «Отправить» и покинуть сайт, зная, что сообщение будет отправлено либо сейчас, либо когда у него будет подключение.
Это полезная функция, но она требует, чтобы работник службы был активен на протяжении всего процесса выборки. Это не проблема для коротких задач, таких как отправка сообщения, но если задача занимает слишком много времени, браузер убьет сервис-воркера, в противном случае это поставит под угрозу конфиденциальность пользователя и заряд батареи.
Итак, что, если вам нужно загрузить что-то, что может занять много времени, например фильм, подкасты или уровни игры. Для этого и нужна фоновая выборка .
Фоновая выборка доступна по умолчанию, начиная с Chrome 74.
Вот короткая двухминутная демонстрация, показывающая традиционное положение вещей в сравнении с использованием фоновой выборки:
Попробуйте демо-версию самостоятельно и просмотрите код .
Как это работает
Фоновая выборка работает следующим образом:
- Вы указываете браузеру выполнить группу выборок в фоновом режиме.
- Браузер извлекает эти данные, отображая прогресс пользователю.
- После завершения или сбоя выборки браузер открывает вашего сервис-воркера и запускает событие, сообщающее вам, что произошло. Здесь вы решаете, что делать с ответами, если что.
Если пользователь закроет страницы вашего сайта после шага 1, ничего страшного, загрузка продолжится. Поскольку выборка хорошо видна и ее легко прервать, нет проблем с конфиденциальностью, связанных со слишком длительной задачей фоновой синхронизации. Поскольку сервис-воркер не работает постоянно, нет опасений, что он может злоупотреблять системой, например майнить биткойны в фоновом режиме.
На некоторых платформах (например, Android) браузер может закрыться после шага 1, поскольку браузер может передать выборку операционной системе.
Если пользователь начинает загрузку в автономном режиме или отключается во время загрузки, фоновая загрузка будет приостановлена и возобновлена позже.
API
Обнаружение функции
Как и в случае с любой новой функцией, вы хотите определить, поддерживает ли ее браузер. Для фоновой выборки это так же просто:
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
Запускаем фоновую выборку
Основной API зависает от регистрации сервис-воркера , поэтому сначала убедитесь, что вы зарегистрировали сервис-воркера. Затем:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
title: 'Episode 5: Interesting things.',
icons: [{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
}],
downloadTotal: 60 * 1024 * 1024,
});
});
backgroundFetch.fetch
принимает три аргумента:
Параметры | |
---|---|
id | string однозначно идентифицирует эту фоновую выборку. |
requests | Array< Request |string> Вещи, которые нужно принести. Строки будут обрабатываться как URL-адреса и превращаться в Request с помощью new Request(theString) .Вы можете получать данные из других источников, если ресурсы позволяют это через CORS . Примечание. Chrome в настоящее время не поддерживает запросы, требующие предварительной проверки CORS. |
options | Объект, который может включать в себя следующее: |
options.title | string Заголовок, который браузер будет отображать вместе с прогрессом. |
options.icons | Array< IconDefinition > Массив объектов с `src`, `size` и `type`. |
options.downloadTotal | number Общий размер тел ответа (после распаковки). Хотя это не является обязательным, настоятельно рекомендуется предоставить его. Он используется, чтобы сообщить пользователю, насколько велика загрузка, и предоставить информацию о ходе загрузки. Если вы не укажете это, браузер сообщит пользователю, что размер неизвестен, и в результате пользователь с большей вероятностью прервет загрузку. Если фоновая загрузка превысит указанное здесь число, она будет прервана. Совершенно нормально, если загрузка меньше, чем |
backgroundFetch.fetch
возвращает обещание, которое разрешается с помощью BackgroundFetchRegistration
. Подробности я расскажу позже. Обещание отклоняется, если пользователь отказался от загрузок или один из предоставленных параметров недействителен.
Предоставление множества запросов для одной фоновой выборки позволяет объединить вещи, которые для пользователя логически являются единым целым. Например, фильм может быть разделен на тысячи ресурсов (типично для MPEG-DASH ) и содержать дополнительные ресурсы, такие как изображения. Уровень игры может быть распределен по множеству ресурсов JavaScript, изображений и аудио. Но для пользователя это просто «фильм» или «уровень».
Получение существующей фоновой выборки
Вы можете получить существующую фоновую выборку следующим образом:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
…передавая идентификатор нужной фоновой выборки. get
возвращает undefined
если нет активной фоновой выборки с этим идентификатором.
Фоновая выборка считается «активной» с момента ее регистрации до тех пор, пока она не завершится успешно, не завершится неудачей или не будет прервана.
Вы можете получить список всех активных фоновых выборок, используя getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Регистрация фоновой выборки
BackgroundFetchRegistration
( bgFetch
в приведенных выше примерах) имеет следующее:
Характеристики | |
---|---|
id | string Идентификатор фоновой выборки. |
uploadTotal | number Количество байтов, которые будут отправлены на сервер. |
uploaded | number Количество успешно отправленных байт. |
downloadTotal | number Значение, предоставленное при регистрации фоновой выборки, или нулевое. |
downloaded | number Количество успешно полученных байтов. Это значение может уменьшиться. Например, если соединение разрывается и загрузку невозможно возобновить, в этом случае браузер перезапускает выборку этого ресурса с нуля. |
result | Одно из следующих:
|
failureReason | Одно из следующих:
|
recordsAvailable | boolean Можно ли получить доступ к основным запросам/ответам? Если это ложное |
Методы | |
abort() | Возвращает Promise<boolean> Прервать фоновую выборку. Возвращенное обещание разрешается с true, если выборка была успешно прервана. |
matchAll(request, opts) | Возвращает Promise<Array<BackgroundFetchRecord>> Получите запросы и ответы. Аргументы здесь такие же, как и у API кэша . Вызов без аргументов возвращает обещание для всех записей. Более подробную информацию смотрите ниже. |
match(request, opts) | Возвращает Promise<BackgroundFetchRecord> То же, что и выше, но разрешается при первом совпадении. |
События | |
progress | Вызывается при изменении любого из uploaded , downloaded , result или failureReason . |
Отслеживание прогресса
Это можно сделать с помощью события progress
. Помните, что downloadTotal
— это любое указанное вами значение или 0
, если вы не указали значение.
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
console.log(`Download progress: ${percent}%`);
});
Получение запросов и ответов
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
представляет собой BackgroundFetchRecord
и выглядит следующим образом:
Характеристики | |
---|---|
request | Request Запрос, который был предоставлен. |
responseReady | Promise<Response> Надуманный ответ. За обещанием стоит ответ, поскольку он, возможно, еще не получен. Промис будет отклонен, если выборка не удастся. |
События для сервисных работников
События | |
---|---|
backgroundfetchsuccess | Все было успешно получено. |
backgroundfetchfailure | Не удалось выполнить одну или несколько операций выборки. |
backgroundfetchabort | Не удалось выполнить одну или несколько выборок. Это действительно полезно, только если вы хотите выполнить очистку связанных данных. |
backgroundfetchclick | Пользователь нажал на пользовательский интерфейс процесса загрузки. |
Объекты событий имеют следующее:
Характеристики | |
---|---|
registration | BackgroundFetchRegistration |
Методы | |
updateUI({ title, icons }) | Позволяет изменить заголовок/значки, которые вы изначально установили. Это необязательно, но при необходимости позволяет предоставить больше контекста. Вы можете сделать это только один раз во время событий backgroundfetchsuccess и backgroundfetchfailure . |
Реакция на успех/неуспех
Мы уже видели событие progress
, но оно полезно только тогда, когда у пользователя открыта страница вашего сайта. Основное преимущество фоновой выборки заключается в том, что все продолжает работать после того, как пользователь покидает страницу или даже закрывает браузер.
Если фоновая выборка успешно завершится, ваш сервис-воркер получит событие backgroundfetchsuccess
, а event.registration
будет регистрацией фоновой выборки.
После этого события полученные запросы и ответы больше не доступны, поэтому, если вы хотите сохранить их, переместите их куда-нибудь, например в API кэша .
Как и в случае с большинством событий сервис-воркера, используйте event.waitUntil
, чтобы сервис-воркер знал, когда событие завершится.
Например, в вашем сервисном работнике:
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
Сбой мог сводиться к одной ошибке 404, которая, возможно, не имела для вас значения, поэтому, возможно, все же стоит скопировать некоторые ответы в кеш, как указано выше.
Реакция на клик
Пользовательский интерфейс, отображающий ход загрузки и результат, является кликабельным. Событие backgroundfetchclick
в сервисном работнике позволяет вам отреагировать на это. Как указано выше, event.registration
будет регистрацией фоновой выборки.
Обычно с этим событием нужно открыть окно:
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
Дополнительные ресурсы
Исправление: в предыдущей версии этой статьи фоновая выборка ошибочно называлась «веб-стандартом». API в настоящее время не находится на стадии разработки стандартов, спецификацию можно найти в WICG в виде проекта отчета группы сообщества.