В этой лаборатории кода показано, как реализовать отказоустойчивый поиск с помощью Workbox. Используемое им демонстрационное приложение содержит поле поиска, которое вызывает конечную точку сервера и перенаправляет пользователя на базовую HTML-страницу.
Мера
Прежде чем добавлять оптимизацию, всегда полезно сначала проанализировать текущее состояние приложения.
- Нажмите Remix to Edit , чтобы сделать проект доступным для редактирования.
- Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим .
В открывшейся новой вкладке проверьте, как сайт ведет себя в автономном режиме:
- Нажмите «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 и выберите «Очистить кеш и полную перезагрузку» , чтобы убедиться, что ваш сервис-воркер обновлен.
- Снова установите в раскрывающемся списке «Регулирование» значение «Автономно» .
- Введите поисковый запрос и снова нажмите кнопку «Поиск» .
Показана резервная HTML-страница:
Запросить разрешение на уведомление
Для простоты автономная страницаviews 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 и выберите «Очистить кеш и полную перезагрузку» , чтобы убедиться, что ваш сервис-воркер обновлен.
- Снова установите в раскрывающемся списке «Регулирование» значение «Автономно» .
- Введите поисковый запрос и снова нажмите кнопку «Поиск» .
- Нажмите подписаться на уведомления .
- Когда Chrome спросит вас, хотите ли вы предоставить приложению разрешение на отправку уведомлений, нажмите «Разрешить» .
- Введите другой поисковый запрос и снова нажмите кнопку «Поиск» .
- Снова установите раскрывающийся список «Регулирование» на «В сети» .
Как только соединение восстановится, появится уведомление:
Заключение
Workbox предоставляет множество встроенных функций, которые сделают ваши PWA более гибкими и привлекательными. В этой лаборатории кода вы изучили, как реализовать API фоновой синхронизации с помощью абстракции Workbox, чтобы гарантировать, что автономные пользовательские запросы не будут потеряны и их можно будет повторить после восстановления соединения. Демо-версия представляет собой простое приложение для поиска, но вы можете использовать аналогичную реализацию для более сложных сценариев и вариантов использования, включая приложения для чата, публикацию сообщений в социальных сетях и т. д.