Про кэширование fetch() в Next.js

У некста 4 уровня кэширования, поэтому он считается темой со звездочкой при его изучении, хотя по идее база. В целом ничего сложного и полно обучалок, но многие путаются между слоями. Попробую сделать заметку-шпаргалку.

Сегодня будет про первые два уровня

Стандартный fetch в нексте переопределен, это все знают. Первый уровень кэширования fetch-запросов — Request Memoization. Под капотом — обычный React.cache(), который кэширует промис запроса в рамках рендера страницы. Т.е. если для одной страницы 5 раз вызывается fetch() с одинаковыми аргументами, то запрос отправится один раз, а остальные 4 запроса вернут промис из первого. Интересное: React.cache() сравнивает параметры по ссылке, и для него нужно выносить одинаковые объектные литералы в переменную, но fetch сериализует свои параметры, т.ч. можно не париться насчет одинаковых литералов.

Второй уровень: Data Cache — это кэширование ответа. Если Request Memoization не нашел промис такого же запроса, то fetch пойдет искать кэш ответа на диске. Найдет — отдаст и в сеть не пойдет. Не найдет — сделает запрос и сохранит ответ в Data Cache.

Как управлять этими кэшами? Request Memoization управлять нельзя, он всегда включен.

Для управления Data Cache есть три параметра:

1. cache 1.1 force-cache — навсегда кэширует запрос. Дефолтный вариант. 1.2 no-store — отключает Data Cache. 1.3. no-cache — выполняет запрос, если в ответе 304 Not Modified — читает ответ из Data Cache. 1.4. default — по дефолту то же что force-cache, но может быть переопределен некоторыми настройками кэша следующих уровней (потом расскажу). 1.5. reload — не читает, но пишет: делает запрос и обновляет ответ в Data Cache. 1.6. only-if-cached — не делает запрос вообще. Если в Data Cache нет данных — fetch падает с ошибкой.

2. next.revalidate 2.1. falseData Cache хранится вечно, сбросить можно только вручную. 2.2. — количество секунд жизни кэша. Если время вышло, то следующий запрос обновит Data Cache, но сам вернет старую версию. Это называется stale-while-revalidate.

3. next.tags: string[] — можно пометить запрос тегами, а потом сбросить его кэш по этим тегам.

Как сбросить Data Cache вручную?

1. Параметр cache: ‘reload’ в следующем вызове fetch. См. выше п. 1.5.

2. revalidateTag(‘cheremsha’) — будет сброшен Data Cache всех запросов, которые мы пометили тегом cheremsha.

3. revalidatePath(‘/path’, ‘page’ | ‘layout’) — так мы сбросим Data Cache всех запросов, которые выполнялись для страницы /path. Если такие же запросы есть на других страницах — их это тоже коснется. Что касается второго аргумента: 3.1. page — сбрасываем только для указанной страницы. Дефолт. 3.2. layout — сбрасываем для указанной страницы и всех ее подстраниц: /path/subpath, /path/[id].

И последнее. При горизонтальном масштабировании Data Cache будет глючить, т.к. в каждом инстансе будет своя версия. Это одно из главных преимуществ хостинга некста на Vercel — там эта проблема решена. Однако решить можно и на своих серверах: нужно просто написать кастомный Cache Handler, чтобы изменить место хранения Data Cache на какой-нибудь Redis, например. Расскажу про это когда закончу истории про кэш.

В следующей серии будет про Full Route Cache.

Про кэширование fetch() в Next.js
У некста 4 уровня кэширования, поэтому он считается темой со звездочкой при его изучении, хотя по идее база | Сетка — социальная сеть от hh.ru