Ключевым аспектом прогрессивных веб-приложений является их надежность; они могут быстро загружать ресурсы, поддерживая интерес пользователей и немедленно предоставляя обратную связь даже при плохих условиях сети. Как это возможно? Благодаря событию fetch
сервисного работника.
Событие выборки
Событие fetch
позволяет нам перехватывать каждый сетевой запрос, сделанный PWA в области действия сервис-воркера, как для запросов одного и того же источника, так и для запросов из разных источников. Помимо навигации и запросов ресурсов, извлечение из установленного сервис-воркера позволяет отображать посещения страниц после первой загрузки сайта без сетевых вызовов.
Обработчик fetch
получает все запросы от приложения, включая URL-адреса и заголовки HTTP, и позволяет разработчику приложения решить, как их обрабатывать.
Ваш сервисный работник может перенаправить запрос в сеть, ответить ранее кэшированным ответом или создать новый ответ. Выбор за вами. Вот простой пример:
self.addEventListener("fetch", event => {
console.log(`URL requested: ${event.request.url}`);
});
Ответ на запрос
Когда запрос поступает в ваш сервис-воркер, вы можете сделать две вещи; вы можете игнорировать его, что позволит ему попасть в сеть, или вы можете ответить на него. Отвечая на запросы внутри вашего сервис-воркера, вы можете выбирать, что и как это будет возвращено в ваш PWA, даже когда пользователь находится в автономном режиме.
Чтобы ответить на входящий запрос, вызовите event.respondWith()
из обработчика событий fetch
, например:
// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
const response = .... // a response or a Promise of response
event.respondWith(response);
});
Вы должны вызвать respondWith()
синхронно и вернуть объект Response . Но вы не можете вызвать respondWith()
после завершения обработчика событий выборки, как в асинхронном вызове. Если вам нужно дождаться полного ответа, вы можете передать обещание в respondWith()
, который выдает ответ.
Создание ответов
Благодаря Fetch API вы можете создавать HTTP-ответы в своем коде JavaScript, и эти ответы можно кэшировать с помощью Cache Storage API и возвращать, как если бы они поступали с веб-сервера.
Чтобы создать ответ, создайте новый объект Response
, задав его тело и такие параметры, как статус и заголовки:
const simpleResponse = new Response("Body of the HTTP response");
const options = {
status: 200,
headers: {
'Content-type': 'text/html'
}
};
const htmlResponse = new Response("<b>HTML</b> content", options)
Ответ из кеша
Теперь, когда вы знаете, как обслуживать HTTP-ответы от сервис-воркера, пришло время использовать интерфейс Caching Storage для хранения ресурсов на устройстве.
Вы можете использовать API хранилища кэша, чтобы проверить, доступен ли запрос, полученный от PWA, в кеше, и если да, ответить с его помощью на respondWith()
. Для этого вам сначала нужно выполнить поиск в кеше. Функция match()
, доступная в интерфейсе caches
верхнего уровня, выполняет поиск во всех хранилищах вашего источника или в одном открытом объекте кэша.
Функция match()
получает HTTP-запрос или URL-адрес в качестве аргумента и возвращает обещание, которое разрешается с помощью ответа, связанного с соответствующим ключом.
// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
console.log(response ? response : "It's not in the cache");
});
// Cache-specific search
caches.open("pwa-assets").then(cache => {
cache.match(urlOrRequest).then(response => {
console.log(response ? response : "It's not in the cache");
});
});
Стратегии кэширования
Обслуживание файлов только из кеша браузера подходит не для всех случаев использования. Например, пользователь или браузер могут удалить кеш. Вот почему вам следует определить свои собственные стратегии доставки ресурсов для вашего PWA. Вы не ограничены одной стратегией кэширования. Вы можете определить разные для разных шаблонов URL. Например, у вас может быть одна стратегия для минимальных ресурсов пользовательского интерфейса, другая для вызовов API и третья для URL-адресов изображений и данных. Для этого прочитайте event.request.url
в ServiceWorkerGlobalScope.onfetch
и проанализируйте его с помощью регулярных выражений или шаблона URL-адреса . (На момент написания шаблон URL-адреса поддерживается не на всех платформах).
Наиболее распространенными стратегиями являются:
- Сначала кэшируйте
- Сначала ищет кэшированный ответ и возвращается в сеть, если он не найден.
- Сеть прежде всего
- Сначала запрашивает ответ из сети и, если ответ не возвращается, проверяет наличие ответа в кеше.
- Устарело при повторной проверке
- Обслуживает ответ из кеша, при этом в фоновом режиме запрашивает последнюю версию и сохраняет ее в кеше для следующего запроса актива.
- Только сеть
- Всегда отвечает ответом из сети или ошибками. Кэш никогда не обращается.
- Только кэш
- Всегда отвечает ответом из кеша или ошибками. С сетью никогда не будут консультироваться. Ресурсы, которые будут обслуживаться с использованием этой стратегии, должны быть добавлены в кеш до того, как они будут запрошены.
Сначала кэшируйте
Используя эту стратегию, сервис-воркер ищет соответствующий запрос в кеше и возвращает соответствующий ответ, если он кэширован. В противном случае он получает ответ из сети (необязательно обновляя кеш для будущих вызовов). Если нет ни ответа кэша, ни ответа сети, запрос завершится ошибкой. Поскольку обслуживание ресурсов без подключения к сети обычно происходит быстрее, в этой стратегии приоритет отдается производительности, а не свежести.
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
// It can update the cache to serve updated content on the next request
return cachedResponse || fetch(event.request);
}
)
)
});
Сеть прежде всего
Эта стратегия является зеркалом стратегии Cache First; он проверяет, может ли запрос быть выполнен из сети, и, если это невозможно, пытается получить его из кэша. Сначала нравится кеш. Если нет ни ответа сети, ни ответа кэша, запрос будет ошибочным. Получение ответа из сети обычно происходит медленнее, чем получение его из кэша. Эта стратегия отдает приоритет обновленному контенту, а не производительности.
self.addEventListener("fetch", event => {
event.respondWith(
fetch(event.request)
.catch(error => {
return caches.match(event.request) ;
})
);
});
Устарело при повторной проверке
Устаревшая стратегия повторной проверки немедленно возвращает кэшированный ответ, затем проверяет сеть на наличие обновлений, заменяя кэшированный ответ, если он найден. Эта стратегия всегда делает сетевой запрос, поскольку даже если кэшированный ресурс будет найден, он попытается обновить то, что было в кеше, тем, что было получено из сети, чтобы использовать обновленную версию в следующем запросе. Таким образом, эта стратегия дает вам возможность воспользоваться преимуществами быстрого обслуживания стратегии кэширования и обновления кэша в фоновом режиме.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
const networkFetch = fetch(event.request).then(response => {
// update the cache with a clone of the network response
const responseClone = response.clone()
caches.open(url.searchParams.get('name')).then(cache => {
cache.put(event.request, responseClone)
})
return response
}).catch(function (reason) {
console.error('ServiceWorker fetch failed: ', reason)
})
// prioritize cached response over network
return cachedResponse || networkFetch
}
)
)
})
Только сеть
Стратегия «только сеть» аналогична тому, как ведут себя браузеры без сервисного работника или API Cache Storage. Запросы вернут ресурс только в том случае, если его можно получить из сети. Это часто полезно для таких ресурсов, как запросы API, доступные только онлайн.
Только кэш
Стратегия только кэширования гарантирует, что запросы никогда не попадут в сеть; на все входящие запросы отвечает предварительно заполненный элемент кэша. Следующий код использует обработчик событий fetch
с методом match
кэш-хранилища только для ответа на кэш:
self.addEventListener("fetch", event => {
event.respondWith(caches.match(event.request));
});
Пользовательские стратегии
Хотя вышеперечисленные стратегии являются распространенными, вы отвечаете за своего сервис-воркера и за обработку запросов. Если ни один из них не подходит вам, создайте свой собственный.
Например, вы можете использовать стратегию «Сначала сеть» с тайм-аутом для определения приоритета обновленного контента, но только в том случае, если ответ появляется в пределах установленного вами порогового значения. Вы также можете объединить кэшированный ответ с ответом сети и создать сложный ответ от сервис-воркера.
Обновление ресурсов
Поддержание актуальности кэшированных ресурсов вашего PWA может оказаться непростой задачей. Хотя устаревшая стратегия повторной проверки является одним из способов сделать это, она не единственная. В главе «Обновление» вы узнаете о различных методах обновления содержимого и ресурсов вашего приложения.