Дізнайтеся про API unstable_cache в Next.js для детального контролю кешування даних, покращуючи продуктивність та досвід користувача в динамічних застосунках.
Нестабільний кеш Next.js: детальний контроль кешування для динамічних застосунків
Next.js здійснив революцію у веброзробці, пропонуючи потужні функції для створення продуктивних та масштабованих застосунків. Однією з його ключових переваг є надійний механізм кешування, який дозволяє розробникам оптимізувати завантаження та рендеринг даних для кращого досвіду користувача. Хоча Next.js надає різні стратегії кешування, API unstable_cache
пропонує новий рівень детального контролю, дозволяючи розробникам налаштовувати поведінку кешування відповідно до конкретних потреб їхніх динамічних застосунків. У цій статті ми розглянемо API unstable_cache
, його можливості, переваги та практичне застосування.
Розуміння кешування в Next.js
Перш ніж заглиблюватися в unstable_cache
, важливо зрозуміти різні рівні кешування в Next.js. Next.js використовує декілька механізмів кешування для підвищення продуктивності:
- Кеш повних маршрутів: Next.js може кешувати цілі маршрути, включаючи HTML та JSON дані, на межі мережі (edge) або в CDN. Це гарантує, що наступні запити до того ж маршруту будуть швидко обслуговуватися з кешу.
- Кеш даних: Next.js автоматично кешує результати операцій завантаження даних. Це запобігає зайвим запитам даних, значно підвищуючи продуктивність.
- Кеш React (useMemo, useCallback): Вбудовані механізми кешування React, такі як
useMemo
таuseCallback
, можуть використовуватися для мемоізації дорогих обчислень та рендерингу компонентів.
Хоча ці механізми кешування є потужними, вони не завжди можуть забезпечити необхідний рівень контролю для складних, динамічних застосунків. Саме тут на допомогу приходить unstable_cache
.
Представляємо API `unstable_cache`
API unstable_cache
в Next.js дозволяє розробникам визначати власні стратегії кешування для окремих операцій завантаження даних. Він надає детальний контроль над:
- Тривалість кешу (TTL): Вкажіть, як довго дані повинні зберігатися в кеші перед їх інвалідацією.
- Теги кешу: Призначайте теги кешованим даним, що дозволяє інвалідувати певні набори даних.
- Генерація ключа кешу: Налаштовуйте ключ, що використовується для ідентифікації кешованих даних.
- Ревалідація кешу: Контролюйте, коли кеш повинен бути ревалідований.
API вважається "нестабільним", оскільки він все ще знаходиться в розробці та може зазнати змін у майбутніх версіях Next.js. Однак він пропонує цінну функціональність для розширених сценаріїв кешування.
Як працює `unstable_cache`
Функція unstable_cache
приймає два основні аргументи:
- Функція, яка завантажує або обчислює дані: Ця функція виконує фактичне отримання або обчислення даних.
- Об'єкт опцій: Цей об'єкт визначає параметри кешування, такі як TTL, теги та ключ.
Ось базовий приклад використання unstable_cache
:
import { unstable_cache } from 'next/cache';
async function getData(id: string) {
return unstable_cache(
async () => {
// Симулюємо завантаження даних з API
await new Promise((resolve) => setTimeout(resolve, 1000));
const data = { id: id, value: `Data for ID ${id}` };
return data;
},
["data", id],
{ tags: ["data", `item:${id}`] }
)();
}
export default async function Page({ params }: { params: { id: string } }) {
const data = await getData(params.id);
return {data.value};
}
У цьому прикладі:
- Функція
getData
використовуєunstable_cache
для кешування операції завантаження даних. - Перший аргумент
unstable_cache
— це асинхронна функція, яка симулює завантаження даних з API. Ми додали затримку в 1 секунду, щоб продемонструвати переваги кешування. - Другий аргумент — це масив, що використовується як ключ. Зміни в елементах масиву призведуть до інвалідації кешу.
- Третій аргумент — це об'єкт, який встановлює опцію
tags
у значення["data", `item:${id}`]
.
Ключові особливості та опції `unstable_cache`
1. Час життя (Time-to-Live, TTL)
Опція revalidate
(раніше `ttl` у попередніх експериментальних версіях) вказує максимальний час (у секундах), протягом якого кешовані дані вважаються дійсними. Після цього часу кеш ревалідується при наступному запиті.
import { unstable_cache } from 'next/cache';
async function getData(id: string) {
return unstable_cache(
async () => {
// Симулюємо завантаження даних з API
await new Promise((resolve) => setTimeout(resolve, 1000));
const data = { id: id, value: `Data for ID ${id}` };
return data;
},
["data", id],
{ tags: ["data", `item:${id}`], revalidate: 60 } // Кешувати на 60 секунд
)();
}
У цьому прикладі дані будуть кешуватися протягом 60 секунд. Через 60 секунд наступний запит ініціює ревалідацію, завантажуючи свіжі дані з API та оновлюючи кеш.
Загальна рекомендація: Встановлюючи значення TTL, враховуйте частоту оновлення даних. Для даних, що часто змінюються, доцільно використовувати коротший TTL. Для відносно статичних даних довший TTL може значно підвищити продуктивність.
2. Теги кешу
Теги кешу дозволяють групувати пов'язані кешовані дані та інвалідувати їх колективно. Це корисно, коли оновлення одного елемента даних впливає на інші пов'язані дані.
import { unstable_cache, revalidateTag } from 'next/cache';
async function getProduct(id: string) {
return unstable_cache(
async () => {
// Симулюємо завантаження даних про продукт з API
await new Promise((resolve) => setTimeout(resolve, 500));
const product = { id: id, name: `Product ${id}`, price: Math.random() * 100 };
return product;
},
["product", id],
{ tags: ["products", `product:${id}`] }
)();
}
async function getCategoryProducts(category: string) {
return unstable_cache(
async () => {
// Симулюємо завантаження продуктів за категорією з API
await new Promise((resolve) => setTimeout(resolve, 500));
const products = Array.from({ length: 3 }, (_, i) => ({ id: `${category}-${i}`, name: `Product ${category}-${i}`, price: Math.random() * 100 }));
return products;
},
["categoryProducts", category],
{ tags: ["products", `category:${category}`] }
)();
}
// Інвалідувати кеш для всіх продуктів та конкретного продукту
async function updateProduct(id: string, newPrice: number) {
// Симулюємо оновлення продукту в базі даних
await new Promise((resolve) => setTimeout(resolve, 500));
// Інвалідувати кеш для продукту та категорії продуктів
revalidateTag("products");
revalidateTag(`product:${id}`);
return { success: true };
}
У цьому прикладі:
- Обидві функції
getProduct
таgetCategoryProducts
використовують тег"products"
. getProduct
також використовує специфічний тег`product:${id}`
.- При виклику
updateProduct
відбувається інвалідація кешу для всіх даних з тегом"products"
та для конкретного продукту за допомогоюrevalidateTag
.
Загальна рекомендація: Використовуйте значущі та послідовні імена тегів. Розгляньте можливість створення стратегії тегування, яка відповідає вашій моделі даних.
3. Генерація ключа кешу
Ключ кешу використовується для ідентифікації кешованих даних. За замовчуванням unstable_cache
генерує ключ на основі аргументів, переданих у функцію. Однак ви можете налаштувати процес генерації ключа, використовуючи другий аргумент `unstable_cache`, який є масивом, що діє як ключ. Коли будь-який з елементів у масиві змінюється, кеш інвалідується.
import { unstable_cache } from 'next/cache';
async function getData(userId: string, sortBy: string) {
return unstable_cache(
async () => {
// Симулюємо завантаження даних з API
await new Promise((resolve) => setTimeout(resolve, 1000));
const data = { userId: userId, sortBy: sortBy, value: `Data for user ${userId}, sorted by ${sortBy}` };
return data;
},
[userId, sortBy],
{ tags: ["user-data", `user:${userId}`] }
)();
}
У цьому прикладі ключ кешу базується на параметрах userId
та sortBy
. Це гарантує, що кеш буде інвалідовано при зміні будь-якого з цих параметрів.
Загальна рекомендація: Переконайтеся, що ваша стратегія генерації ключів кешу є послідовною та враховує всі відповідні фактори, що впливають на дані. Розгляньте можливість використання хеш-функції для створення унікального ключа зі складних структур даних.
4. Ручна ревалідація
Функція `revalidateTag` дозволяє вручну інвалідувати кеш для даних, пов'язаних з певними тегами. Це корисно, коли вам потрібно оновити кеш у відповідь на події, які не викликані безпосередньо запитом користувача, наприклад, фонове завдання або вебхук.
import { revalidateTag } from 'next/cache';
async function handleWebhook(payload: any) {
// Обробляємо дані вебхука
// Інвалідуємо кеш для пов'язаних даних
revalidateTag("products");
revalidateTag(`product:${payload.productId}`);
}
Загальна рекомендація: Використовуйте ручну ревалідацію стратегічно. Надмірна інвалідація може звести нанівець переваги кешування, тоді як недостатня інвалідація може призвести до застарілих даних.
Практичні випадки використання `unstable_cache`
1. Динамічний контент з нечастими оновленнями
Для вебсайтів з динамічним контентом, який не змінюється дуже часто (наприклад, дописи в блозі, статті новин), ви можете використовувати unstable_cache
з довшим TTL для кешування даних на тривалий період. Це зменшує навантаження на ваш бекенд та покращує час завантаження сторінок.
2. Дані, специфічні для користувача
Для даних, специфічних для користувача (наприклад, профілі користувачів, кошики для покупок), ви можете використовувати unstable_cache
з ключами кешу, що включають ідентифікатор користувача. Це гарантує, що кожен користувач бачить свої власні дані і що кеш інвалідується при зміні даних користувача.
3. Дані в реальному часі з допустимістю застарілих даних
Для застосунків, що відображають дані в реальному часі (наприклад, курси акцій, стрічки соціальних мереж), ви можете використовувати unstable_cache
з коротким TTL для забезпечення оновлень майже в реальному часі. Це збалансовує потребу в актуальних даних з перевагами кешування для продуктивності.
4. A/B тестування
Під час A/B тестування важливо кешувати варіант експерименту, призначений користувачеві, щоб забезпечити послідовний досвід. `unstable_cache` можна використовувати для кешування вибраного варіанту, використовуючи ID користувача як частину ключа кешу.
Переваги використання `unstable_cache`
- Покращена продуктивність: Кешуючи дані,
unstable_cache
зменшує навантаження на ваш бекенд та покращує час завантаження сторінок. - Зниження витрат на бекенд: Кешування зменшує кількість запитів до вашого бекенду, що може знизити витрати на інфраструктуру.
- Покращений досвід користувача: Швидший час завантаження сторінок та плавніша взаємодія призводять до кращого досвіду користувача.
- Детальний контроль:
unstable_cache
надає гранульований контроль над поведінкою кешування, дозволяючи вам налаштувати його відповідно до конкретних потреб вашого застосунку.
Рекомендації та найкращі практики
- Стратегія інвалідації кешу: Розробіть чітко визначену стратегію інвалідації кешу, щоб забезпечити його оновлення при зміні даних.
- Вибір TTL: Вибирайте відповідні значення TTL на основі частоти оновлення даних та чутливості вашого застосунку до застарілих даних.
- Проєктування ключів кешу: Ретельно проєктуйте ключі кешу, щоб вони були унікальними та послідовними.
- Моніторинг та логування: Відстежуйте продуктивність вашого кешу та логуйте влучання та промахи кешу для виявлення потенційних проблем.
- Кешування на межі мережі (edge) проти кешування в браузері: Враховуйте відмінності між кешуванням на межі мережі (CDN) та кешуванням у браузері. Кешування на межі мережі є спільним для всіх користувачів, тоді як кешування в браузері є специфічним для кожного користувача. Вибирайте відповідну стратегію кешування залежно від типу даних та вимог вашого застосунку.
- Обробка помилок: Впроваджуйте надійну обробку помилок для коректної обробки промахів кешу та запобігання поширенню помилок до користувача. Розгляньте можливість використання резервного механізму для отримання даних з бекенду, якщо кеш недоступний.
- Тестування: Ретельно тестуйте вашу реалізацію кешування, щоб переконатися, що вона працює належним чином. Використовуйте автоматизовані тести для перевірки логіки інвалідації та ревалідації кешу.
`unstable_cache` проти кешування `fetch` API
Next.js також надає вбудовані можливості кешування через fetch
API. За замовчуванням Next.js автоматично кешує результати запитів fetch
. Однак unstable_cache
пропонує більшу гнучкість та контроль, ніж кешування `fetch` API.
Ось порівняння двох підходів:
Функція | `unstable_cache` | `fetch` API |
---|---|---|
Контроль над TTL | Явно налаштовується за допомогою опції revalidate . |
Неявно керується Next.js, але можна вплинути за допомогою опції revalidate в параметрах fetch . |
Теги кешу | Підтримує теги кешу для інвалідації пов'язаних даних. | Немає вбудованої підтримки тегів кешу. |
Налаштування ключа кешу | Дозволяє налаштовувати ключ кешу за допомогою масиву значень, які використовуються для його побудови. | Обмежені можливості налаштування. Ключ генерується з URL-адреси запиту. |
Ручна ревалідація | Підтримує ручну ревалідацію за допомогою revalidateTag . |
Обмежена підтримка ручної ревалідації. |
Гранулярність кешування | Дозволяє кешувати окремі операції завантаження даних. | В основному зосереджено на кешуванні HTTP-відповідей. |
Загалом, використовуйте кешування `fetch` API для простих сценаріїв завантаження даних, де стандартна поведінка кешування є достатньою. Використовуйте unstable_cache
для складніших сценаріїв, де вам потрібен детальний контроль над поведінкою кешування.
Майбутнє кешування в Next.js
API unstable_cache
є важливим кроком уперед у можливостях кешування Next.js. По мірі розвитку API ми можемо очікувати ще потужніших функцій та більшої гнучкості в управлінні кешуванням даних. Слідкувати за останніми розробками в кешуванні Next.js є вирішальним для створення високопродуктивних та масштабованих застосунків.
Висновок
API unstable_cache
від Next.js пропонує розробникам безпрецедентний контроль над кешуванням даних, дозволяючи їм оптимізувати продуктивність та досвід користувача в динамічних застосунках. Розуміючи особливості та переваги unstable_cache
, ви можете використовувати його потужність для створення швидших, більш масштабованих та чутливих вебастосунків. Не забувайте ретельно продумувати свою стратегію кешування, вибирати відповідні значення TTL, ефективно проєктувати ключі кешу та відстежувати продуктивність кешу для досягнення оптимальних результатів. Відкрийте для себе майбутнє кешування в Next.js та розкрийте повний потенціал ваших вебастосунків.