В этой лабораторной работе показано, как реализовать отказоустойчивый поиск с помощью Workbox. Используемое демо-приложение содержит поле поиска, которое вызывает конечную точку сервера и перенаправляет пользователя на простую HTML-страницу.
Мера
Перед добавлением оптимизаций всегда полезно проанализировать текущее состояние приложения.
- Нажмите «Ремикс для редактирования», чтобы сделать проект редактируемым.
- Для предварительного просмотра сайта нажмите «Просмотреть приложение» . Затем нажмите «Полный экран».
.
В новой вкладке, которая только что открылась, проверьте, как ведет себя сайт при переходе в автономный режим:
- Нажмите `Control+Shift+J` (или `Command+Option+J` на Mac), чтобы открыть DevTools.
- Откройте вкладку Сеть .
- Откройте Chrome DevTools и выберите панель «Сеть».
- В раскрывающемся списке Регулирование выберите Автономно .
- В демо-приложении введите поисковый запрос, затем нажмите кнопку «Поиск» .
Отображается стандартная страница ошибки браузера:
Предоставьте запасной вариант ответа
Service Worker содержит код для добавления автономной страницы в список предварительного кэширования , поэтому ее всегда можно кэшировать при событии install
Service Worker.
Обычно вам нужно указать Workbox добавить этот файл в список предварительного кэширования во время сборки, интегрировав библиотеку с выбранным вами инструментом сборки (например, webpack или gulp ).
Для простоты мы уже сделали это за вас. Следующий код в public/sw.js
реализует это:
const FALLBACK_HTML_URL = '/index_offline.html';
…
workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);
Затем добавьте код для использования автономной страницы в качестве резервного ответа:
- Чтобы просмотреть исходный текст, нажмите « Просмотреть исходный текст» .
- Добавьте следующий код в конец
public/sw.js
:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());
workbox.routing.setCatchHandler(({event}) => {
switch (event.request.destination) {
case 'document':
return caches.match(FALLBACK_HTML_URL);
break;
default:
return Response.error();
}
});
Код делает следующее:
- Определяет стратегию «Только сеть» по умолчанию, которая будет применяться ко всем запросам.
- Объявляет глобальный обработчик ошибок, вызывая
workbox.routing.setCatchHandler()
для обработки невыполненных запросов. При запросах документов возвращается резервная офлайн-страница HTML.
Чтобы проверить эту функциональность:
- Вернитесь на другую вкладку, на которой запущено ваше приложение.
- Установите в раскрывающемся списке Регулирование значение Онлайн .
- Нажмите кнопку «Назад» в Chrome, чтобы вернуться на страницу поиска.
- Убедитесь, что флажок Отключить кэш в DevTools отключен.
- Нажмите и удерживайте кнопку «Перезагрузить» в Chrome и выберите «Очистить кэш и принудительно перезагрузить», чтобы убедиться, что ваш Service Worker обновлен.
- Снова установите в раскрывающемся списке «Регулирование » значение «Оффлайн» .
- Введите поисковый запрос и снова нажмите кнопку «Поиск» .
Показана резервная HTML-страница:
Запрос разрешения на уведомление
Для простоты автономная страница views/index_offline.html
уже содержит код для запроса разрешений на уведомления в блоке скрипта внизу:
function requestNotificationPermission(event) {
event.preventDefault();
Notification.requestPermission().then(function (result) {
showOfflineText(result);
});
}
Код делает следующее:
- Когда пользователь нажимает кнопку «Подписаться на уведомления», вызывается функция
requestNotificationPermission()
, которая, в свою очередь, вызываетNotification.requestPermission()
для отображения запроса на разрешение браузера по умолчанию. Промис выполняется с разрешением, выбранным пользователем:granted
,denied
) илиdefault
. - Передает разрешенное разрешение
showOfflineText()
для показа соответствующего текста пользователю.
Сохраняйте запросы в автономном режиме и повторяйте попытки, когда снова будете в сети
Затем реализуйте фоновую синхронизацию Workbox для сохранения автономных запросов, чтобы их можно было повторить, когда браузер обнаружит, что соединение восстановлено.
- Откройте
public/sw.js
для редактирования. - Добавьте следующий код в конец файла:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
maxRetentionTime: 60,
onSync: async ({queue}) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
const response = await fetch(entry.request);
const cache = await caches.open('offline-search-responses');
const offlineUrl = `${entry.request.url}¬ification=true`;
cache.put(offlineUrl, response);
showNotification(offlineUrl);
} catch (error) {
await this.unshiftRequest(entry);
throw error;
}
}
},
});
Код делает следующее:
-
workbox.backgroundSync.Plugin
содержит логику добавления невыполненных запросов в очередь для повторной попытки. Эти запросы будут сохранены в IndexedDB . -
maxRetentionTime
указывает время, в течение которого запрос может быть повторен. В данном случае мы выбрали 60 минут (по истечении которых запрос будет отклонён). -
onSync
— самая важная часть этого кода. Этот обратный вызов будет вызван при восстановлении соединения, чтобы запросы из очереди были извлечены и извлечены из сети. - Сетевой ответ добавляется в кэш
offline-search-responses
с добавлением параметра запроса¬ification=true
, чтобы эта запись кэша могла быть извлечена, когда пользователь нажимает на уведомление.
Чтобы интегрировать фоновую синхронизацию с вашим сервисом, определите стратегию NetworkOnly для запросов к URL поиска ( /search_action
) и передайте ранее определенный bgSyncPlugin
. Добавьте следующий код в конец файла public/sw.js
:
const matchSearchUrl = ({url}) => {
const notificationParam = url.searchParams.get('notification');
return url.pathname === '/search_action' && !(notificationParam === 'true');
};
workbox.routing.registerRoute(
matchSearchUrl,
new workbox.strategies.NetworkOnly({
plugins: [bgSyncPlugin],
}),
);
Это сообщает Workbox, что нужно всегда подключаться к сети и в случае сбоя запросов использовать логику фоновой синхронизации.
Затем добавьте следующий код в конец файла public/sw.js
чтобы определить стратегию кэширования запросов, поступающих от уведомлений. Используйте стратегию CacheFirst , чтобы их можно было обслуживать из кэша.
const matchNotificationUrl = ({url}) => {
const notificationParam = url.searchParams.get('notification');
return (url.pathname === '/search_action' && (notificationParam === 'true'));
};
workbox.routing.registerRoute(matchNotificationUrl,
new workbox.strategies.CacheFirst({
cacheName: 'offline-search-responses',
})
);
Наконец, добавьте код для показа уведомлений:
function showNotification(notificationUrl) {
if (Notification.permission) {
self.registration.showNotification('Your search is ready!', {
body: 'Click to see you search result',
icon: '/img/workbox.jpg',
data: {
url: notificationUrl
}
});
}
}
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(
clients.openWindow(event.notification.data.url)
);
});
Протестируйте функцию
- Вернитесь на другую вкладку, на которой запущено ваше приложение.
- Установите в раскрывающемся списке Регулирование значение Онлайн .
- Нажмите кнопку «Назад» в Chrome, чтобы вернуться на страницу поиска.
- Нажмите и удерживайте кнопку «Перезагрузить» в Chrome и выберите «Очистить кэш и принудительно перезагрузить», чтобы убедиться, что ваш Service Worker обновлен.
- Снова установите в раскрывающемся списке «Регулирование » значение «Оффлайн» .
- Введите поисковый запрос и снова нажмите кнопку «Поиск» .
- Нажмите «Подписаться на уведомления» .
- Когда Chrome спросит вас, хотите ли вы предоставить приложению разрешение на отправку уведомлений, нажмите Разрешить .
- Введите другой поисковый запрос и снова нажмите кнопку «Поиск» .
- Снова установите в раскрывающемся списке «Регулирование » значение «Онлайн» .
Как только соединение восстановится, появится уведомление:
Заключение
Workbox предоставляет множество встроенных функций, которые сделают ваши PWA более надёжными и интересными. В этой лабораторной работе вы изучили, как реализовать API фоновой синхронизации с помощью абстракции Workbox, чтобы гарантировать, что запросы пользователей, отправленные офлайн, не будут потеряны и их можно будет повторить после восстановления соединения. Демоверсия представляет собой простое поисковое приложение, но вы можете использовать похожую реализацию для более сложных сценариев и вариантов использования, включая чаты, публикацию сообщений в социальных сетях и т. д.