Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Где определяется кэширование
Кэширование в веб-приложениях определяется на нескольких уровнях и регулируется разными механизмами. Это важнейшая тема для оптимизации производительности фронтенда.
Уровни кэширования
1. HTTP кэширование (самое главное)
Регулируется HTTP заголовками в ответе сервера. Это контролирует, как браузер и промежуточные прокси (CDN, nginx) сохраняют и переиспользуют ресурсы.
Основные заголовки:
// На сервере (Express.js пример)
app.get('/api/products', (req, res) => {
// Разрешить браузеру кэшировать на 1 час
res.set('Cache-Control', 'public, max-age=3600');
res.json(productsData);
});
app.get('/images/logo.png', (req, res) => {
// Кэшировать на 1 год (для статических assets с версией)
res.set('Cache-Control', 'public, max-age=31536000');
res.sendFile('logo.png');
});
app.get('/api/user-profile', (req, res) => {
// Не кэшировать (данные персональные)
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
res.json(userProfile);
});
Значения Cache-Control:
public— кэш может быть использован браузером и промежуточными кэшами (CDN)private— кэш только для браузера пользователя (не для CDN/прокси)max-age=3600— кэшировать на 3600 секунд (1 час)no-cache— всегда проверить с сервером перед использованием из кэшаno-store— не кэшировать вообщеmust-revalidate— кэш истекает, если есть ошибка сети
2. ETag и Last-Modified (переиспользование кэша)
Эти заголовки позволяют браузеру проверить, изменился ли ресурс:
// На сервере
app.get('/api/data', (req, res) => {
const data = { id: 1, name: 'Item' };
const etag = '"abc123"';
res.set('ETag', etag);
res.set('Cache-Control', 'no-cache');
if (req.get('If-None-Match') === etag) {
return res.sendStatus(304);
}
res.json(data);
});
3. Service Workers (кэширование на клиенте)
Дает полный контроль над кэшированием с клиентской стороны:
// service-worker.js
const CACHE_NAME = 'my-app-v1';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
'/',
'/css/style.css',
'/js/app.js'
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
if (response) return response;
return fetch(event.request);
})
);
});
4. localStorage и sessionStorage
Для приложения, когда HTTP кэширования недостаточно:
localStorage.setItem('userData', JSON.stringify({
id: 1,
name: 'John',
timestamp: Date.now()
}));
const cached = JSON.parse(localStorage.getItem('userData'));
if (cached && Date.now() - cached.timestamp < 3600000) {
useData(cached);
} else {
fetchFreshData();
}
5. React useMemo для кэширования вычислений
function UserProfile({ userId }) {
const userData = useMemo(() => {
return fetchUserData(userId);
}, [userId]);
return <div>{userData.name}</div>;
}
Практический пример: API клиент с кэшированием
class ApiClient {
constructor() {
this.cache = new Map();
}
async get(url, options = {}) {
const cacheKey = url + JSON.stringify(options);
if (this.cache.has(cacheKey)) {
const { value, expiry } = this.cache.get(cacheKey);
if (Date.now() < expiry) {
return value;
}
this.cache.delete(cacheKey);
}
const data = await fetch(url, options).then(r => r.json());
this.cache.set(cacheKey, {
value: data,
expiry: Date.now() + 300000
});
return data;
}
}
Стратегии кэширования
Cache First: для статических ассетов
event.respondWith(
caches.match(event.request)
.then((response) => response || fetch(event.request))
);
Network First: для API данных
event.respondWith(
fetch(event.request)
.catch(() => caches.match(event.request))
);
Вывод
Кэширование определяется на разных уровнях:
- HTTP заголовки (Cache-Control, ETag) — основной способ
- Service Workers — для offline режима
- localStorage/sessionStorage — для персистентных данных
- JavaScript Map — для временного кэша в памяти
- useMemo — для кэша вычислений в React
Для оптимальной производительности используй всё вместе в зависимости от случая.