← Назад к вопросам
Как работает кэширование через Service Worker?
2.0 Middle🔥 161 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Кэширование через Service Worker
Service Worker - это скрипт, работающий в фоне браузера отдельно от основной страницы. Он может перехватывать сетевые запросы и кэшировать данные для оффлайн работы.
Жизненный цикл Service Worker
Service Worker проходит несколько фаз:
// 1. INSTALL фаза
self.addEventListener("install", (event) => {
console.log("Service Worker установлен");
// Здесь кэшируем ресурсы при первой установке
event.waitUntil(
caches.open("v1").then((cache) => {
return cache.addAll([
"/",
"/index.html",
"/styles.css",
"/app.js"
]);
})
);
});
// 2. ACTIVATE фаза
self.addEventListener("activate", (event) => {
console.log("Service Worker активирован");
// Очищаем старые версии кэша
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== "v1") {
return caches.delete(cacheName);
}
})
);
})
);
});
// 3. FETCH фаза (перехват запросов)
self.addEventListener("fetch", (event) => {
console.log("Перехвачен запрос", event.request.url);
// Стратегия: кэш сначала, потом сеть
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});
Стратегии кэширования
Стратегия 1: Cache First (Кэш в приоритете)
Используй для статических ресурсов:
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// Если в кэше - вернуть из кэша
if (response) {
return response;
}
// Если нет в кэше - получить с сервера
return fetch(event.request).then((response) => {
// Кэшировать новый ответ
if (!response || response.status !== 200) {
return response;
}
const clonedResponse = response.clone();
caches.open("v1").then((cache) => {
cache.put(event.request, clonedResponse);
});
return response;
});
})
);
});
Стратегия 2: Network First (Сеть в приоритете)
Используй для API запросов и контента:
self.addEventListener("fetch", (event) => {
event.respondWith(
fetch(event.request)
.then((response) => {
// Успешный ответ - кэшировать и вернуть
if (response && response.status === 200) {
const clonedResponse = response.clone();
caches.open("api-v1").then((cache) => {
cache.put(event.request, clonedResponse);
});
}
return response;
})
.catch(() => {
// Нет сети - использовать кэш
return caches.match(event.request).then((response) => {
return response || new Response("Offline", {
status: 503,
statusText: "Service Unavailable"
});
});
})
);
});
Стратегия 3: Stale While Revalidate
Вернуть кэш сразу, параллельно обновить:
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.open("v1").then((cache) => {
return cache.match(event.request).then((response) => {
// Параллельно получаем свежие данные с сервера
const fetchPromise = fetch(event.request).then((response) => {
// Обновляем кэш в фоне
if (response && response.status === 200) {
cache.put(event.request, response.clone());
}
return response;
});
// Вернуть кэш сразу, или ждать свежих данных
return response || fetchPromise;
});
})
);
});
Регистрация Service Worker в приложении
// На фронтенде (main.js или index.js)
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/service-worker.js").then(
(registration) => {
console.log("Service Worker зарегистрирован", registration);
},
(error) => {
console.error("Service Worker не зарегистрирован", error);
}
);
});
}
Работа с Cache API
// Открыть или создать кэш
const cache = await caches.open("v1");
// Добавить ресурсы в кэш
await cache.addAll([
"/index.html",
"/styles.css",
"/app.js"
]);
// Добавить одиночный запрос
await cache.add("/page.html");
// Добавить запрос с ответом
await cache.put(
new Request("/data.json"),
new Response(JSON.stringify({ data: "value" }))
);
// Получить из кэша
const response = await cache.match("/index.html");
// Удалить из кэша
await cache.delete("/page.html");
// Удалить весь кэш
await caches.delete("v1");
// Список всех кэшей
const cacheNames = await caches.keys();
console.log(cacheNames);
Практический пример с версионированием
const CACHE_VERSION = "v2";
const CACHE_NAME = `my-app-${CACHE_VERSION}`;
const URLS_TO_CACHE = [
"/",
"/index.html",
"/styles.css",
"/app.js",
"/offline.html"
];
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(URLS_TO_CACHE);
})
);
// Пропустить ожидание, сразу активировать
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (!cacheName.startsWith("my-app-")) return;
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
// Контролировать все клиенты сразу
self.clients.claim();
});
self.addEventListener("fetch", (event) => {
const url = new URL(event.request.url);
// API запросы - network first
if (url.pathname.startsWith("/api/")) {
event.respondWith(
fetch(event.request)
.then(response => {
const cache = caches.open(CACHE_NAME);
cache.then(c => c.put(event.request, response.clone()));
return response;
})
.catch(() => caches.match(event.request))
);
}
// Статические файлы - cache first
else {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
}).catch(() => caches.match("/offline.html"))
);
}
});
Важные моменты
- Service Worker работает только на HTTPS (кроме localhost)
- Область действия ограничена путем регистрации
- Можно иметь несколько кэшей с разными именами
- Обновление Service Worker требует явной переустановки
- Используй версионирование для управления кэшем
- Для тестирования: Chrome DevTools -> Application -> Service Workers