Как решать проблему несогласованности данных при кэшировании
Что проверяют
Понимаете ли вы, что на фронтенде кэшей несколько и каждый устаревает по-своему: HTTP-кэш браузера, CDN, Service Worker и кэш данных в клиентской библиотеке. Следом обычно спрашивают, как после мутации обновить все места, где показаны те же данные.
Как отвечать
Разложите ответ по уровням:
- HTTP-кэш: статика собирается с хэшем в имени файла и отдаётся с
Cache-Control: max-age=31536000, immutable, аindex.htmlсno-cache, чтобы браузер сверялся черезETag. Для API подходитstale-while-revalidate, если короткое устаревание допустимо; - Service Worker: стратегия (cache first или network first) выбирается под тип ресурса, а при деплое нужна новая версия кэша и удаление старых в событии
activate; - кэш данных: в TanStack Query
staleTimeпо умолчанию 0, данные считаются устаревшими сразу. После мутации вызываютinvalidateQueriesпо ключу или правят кэш черезsetQueryData. В RTK Query ту же роль играютprovidesTagsиinvalidatesTags, в Apollo нормализованный кэш по__typenameиid; - оптимистичные обновления: интерфейс меняется сразу, но при ошибке нужен откат к сохранённому снимку;
- гонки ответов: при быстром поиске или смене фильтра старый ответ приходит позже нового и затирает его. Лечится
AbortControllerили сверкой ключа запроса; - вкладки: состояние между вкладками синхронизируют через
BroadcastChannelили событиеstorage.
Сильный ответ заканчивается компромиссом: для каждого типа данных вы решаете, какое устаревание допустимо. Цена и остаток на складе живут иначе, чем справочник стран.
Где спотыкаются
Инвалидируют список, но забывают карточку того же объекта, или наоборот. Помогает единая схема ключей вроде ['todos', id], где список и карточка делят общий префикс.
Кэшируют index.html надолго. После деплоя пользователи получают старый HTML, который ссылается на уже удалённые чанки, и приложение не грузится.
Складывают данные в localStorage без версии схемы. После релиза код читает старую структуру и падает у тех, чей кэш остался с прошлой недели.