Service Worker предоставляет два фундаментальных подхода к работе с кэшем:
Библиотека sw-precache реализует первый подход, автоматизируя процесс создания списка ресурсов и генерации Service Worker.
Precache — это стратегия, при которой набор файлов определяется заранее и гарантированно оказывается в кэше до начала работы приложения.
Ключевые характеристики:
install Service
Worker;sw-precache — это инструмент сборки, который:
Пример конфигурации:
const swPrecache = require('sw-precache');
swPrecache.write('./service-worker.js', {
staticFileGlobs: [
'public/**/*.html',
'public/**/*.css',
'public/**/*.js',
'public/images/**/*.*'
],
stripPrefix: 'public/'
});
Во время установки Service Worker выполняется:
self.addEventListener('install', event => {
event.waitUntil(
caches.open('precache-v1').then(cache => {
return cache.addAll([
'/',
'/index.html',
'/main.css',
'/app.js'
]);
})
);
});
Особенности:
cache.addAll() гарантирует атомарность: либо кэшируются
все ресурсы, либо ни один.Precache требует строгого контроля версий:
app.3f5a8c.js
style.a91d2e.css
sw-precache автоматически:
После установки Service Worker перехватывает сетевые запросы:
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
Поведение:
Runtime-кэширование работает иначе:
Пример:
self.addEventListener('fetch', event => {
event.respondWith(
caches.open('runtime').then(cache => {
return fetch(event.request).then(response => {
cache.put(event.request, response.clone());
return response;
});
})
);
});
| Подход | Когда происходит |
|---|---|
| Precache | При установке SW |
| Runtime | Во время выполнения |
| Подход | Контроль |
|---|---|
| Precache | Полный, список фиксирован |
| Runtime | Частичный, зависит от запросов |
| Подход | Офлайн-доступ |
|---|---|
| Precache | Гарантирован |
| Runtime | Частичный |
Precache:
Runtime:
Precache:
Runtime:
Runtime-кэширование обычно использует стратегии:
Пример стратегии Cache First:
event.respondWith(
caches.match(event.request).then(cached => {
return cached || fetch(event.request);
})
);
Подходит для:
Используется для:
На практике применяется гибрид:
Пример архитектуры:
// precache (генерируется sw-precache)
// runtime
self.addEventListener('fetch', event => {
if (event.request.url.includes('/api/')) {
event.respondWith(networkFirstStrategy(event.request));
}
});
1. Отсутствие версионирования
2. Слишком большой список файлов
3. Кэширование API-ответов
4. Игнорирование обновления Service Worker
Процесс:
Контроль обновления:
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys => {
return Promise.all(
keys.map(key => {
if (key !== 'precache-v2') {
return caches.delete(key);
}
})
);
})
);
});
Именно precache обеспечивает мгновенную загрузку и офлайн-работу, тогда как runtime-кэширование отвечает за гибкость и актуальность данных в процессе эксплуатации приложения.