API unstable_cache در Next.js را برای کنترل دقیق کش داده، بهبود عملکرد و تجربه کاربری در برنامههای پویا کاوش کنید.
unstable_cache در Next.js: کنترل دقیق کش برای برنامههای پویا
Next.js انقلابی در توسعه وب ایجاد کرده است و ویژگیهای قدرتمندی برای ساخت برنامههای کاربردی با عملکرد بالا و مقیاسپذیر ارائه میدهد. یکی از نقاط قوت اصلی آن، مکانیسم کشینگ قدرتمند آن است که به توسعهدهندگان اجازه میدهد تا واکشی داده و رندرینگ را برای تجربه کاربری روانتر بهینه کنند. در حالی که Next.js استراتژیهای مختلف کشینگ را ارائه میدهد، API unstable_cache
سطح جدیدی از کنترل دقیق را ارائه میدهد و به توسعهدهندگان این امکان را میدهد که رفتار کشینگ را متناسب با نیازهای خاص برنامههای پویای خود تنظیم کنند. این مقاله به بررسی API unstable_cache
، قابلیتها، مزایا و کاربردهای عملی آن میپردازد.
درک کشینگ در Next.js
قبل از پرداختن به unstable_cache
، درک لایههای مختلف کشینگ در Next.js ضروری است. Next.js از چندین مکانیسم کشینگ برای بهبود عملکرد استفاده میکند:
- کش مسیر کامل (Full Route Cache): Next.js میتواند مسیرهای کامل، شامل HTML و دادههای JSON را در لبه (edge) یا در یک CDN کش کند. این تضمین میکند که درخواستهای بعدی برای همان مسیر به سرعت از کش ارائه شوند.
- کش داده (Data Cache): Next.js به طور خودکار نتایج عملیات واکشی داده را کش میکند. این کار از واکشی دادههای تکراری جلوگیری کرده و به طور قابل توجهی عملکرد را بهبود میبخشد.
- کش ریاکت (useMemo, useCallback): مکانیسمهای کشینگ داخلی ریاکت، مانند
useMemo
وuseCallback
، میتوانند برای مموایز کردن (memoize) محاسبات سنگین و رندرینگ کامپوننتها استفاده شوند.
در حالی که این مکانیسمهای کشینگ قدرتمند هستند، ممکن است همیشه سطح کنترل مورد نیاز برای برنامههای پیچیده و پویا را فراهم نکنند. اینجاست که unstable_cache
وارد عمل میشود.
معرفی API `unstable_cache`
API unstable_cache
در Next.js به توسعهدهندگان اجازه میدهد تا استراتژیهای کشینگ سفارشی را برای عملیات واکشی داده فردی تعریف کنند. این API کنترل دقیقی بر موارد زیر فراهم میکند:
- مدت زمان کش (TTL): مشخص کردن مدت زمانی که داده باید قبل از بیاعتبار شدن در کش باقی بماند.
- تگهای کش (Cache Tags): اختصاص تگ به دادههای کش شده، که به شما امکان میدهد مجموعههای خاصی از دادهها را بیاعتبار کنید.
- تولید کلید کش (Cache Key Generation): سفارشیسازی کلیدی که برای شناسایی دادههای کش شده استفاده میشود.
- اعتبارسنجی مجدد کش (Cache Revalidation): کنترل زمان اعتبارسنجی مجدد کش.
این API "ناپایدار" (unstable) در نظر گرفته میشود زیرا هنوز در حال توسعه است و ممکن است در نسخههای آینده Next.js دستخوش تغییر شود. با این حال، عملکرد ارزشمندی برای سناریوهای پیشرفته کشینگ ارائه میدهد.
unstable_cache
چگونه کار میکند
تابع unstable_cache
دو آرگومان اصلی میگیرد:
- یک تابع که داده را واکشی یا محاسبه میکند: این تابع بازیابی یا محاسبه واقعی داده را انجام میدهد.
- یک شیء گزینهها (options object): این شیء گزینههای کشینگ مانند 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`
۱. زمان بقا (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 } // کش برای ۶۰ ثانیه
)();
}
در این مثال، داده برای ۶۰ ثانیه کش میشود. پس از ۶۰ ثانیه، درخواست بعدی باعث اعتبارسنجی مجدد شده، دادههای تازه از API واکشی شده و کش بهروزرسانی میشود.
نکته کلی: هنگام تنظیم مقادیر TTL، فرکانس بهروزرسانی دادهها را در نظر بگیرید. برای دادههایی که به طور مکرر تغییر میکنند، TTL کوتاهتر مناسب است. برای دادههای نسبتاً ثابت، TTL طولانیتر میتواند به طور قابل توجهی عملکرد را بهبود بخشد.
۲. تگهای کش (Cache Tags)
تگهای کش به شما این امکان را میدهند که دادههای کش شده مرتبط را گروهبندی کرده و آنها را به صورت جمعی بیاعتبار کنید. این ویژگی زمانی مفید است که بهروزرسانی یک بخش از داده بر سایر دادههای مرتبط تأثیر بگذارد.
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
فراخوانی میشود، با استفاده ازrevalidateTag
، کش را برای تمام دادههای تگ شده با"products"
و محصول خاص بیاعتبار میکند.
نکته کلی: از نامهای تگ معنادار و سازگار استفاده کنید. یک استراتژی تگگذاری که با مدل داده شما هماهنگ باشد، ایجاد کنید.
۳. تولید کلید کش
کلید کش برای شناسایی دادههای کش شده استفاده میشود. به طور پیشفرض، 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
است. این تضمین میکند که کش هنگام تغییر هر یک از این پارامترها بیاعتبار شود.
نکته کلی: اطمینان حاصل کنید که استراتژی تولید کلید کش شما سازگار است و تمام عوامل مرتبطی که بر دادهها تأثیر میگذارند را در نظر میگیرد. برای ایجاد یک کلید منحصر به فرد از ساختارهای داده پیچیده، استفاده از یک تابع هش را در نظر بگیرید.
۴. اعتبارسنجی مجدد دستی
تابع `revalidateTag` به شما امکان میدهد تا به صورت دستی کش را برای دادههای مرتبط با تگهای خاص بیاعتبار کنید. این ویژگی زمانی مفید است که نیاز دارید کش را در پاسخ به رویدادهایی که مستقیماً توسط درخواست کاربر ایجاد نشدهاند، مانند یک کار پسزمینه (background job) یا یک وبهوک (webhook)، بهروزرسانی کنید.
import { revalidateTag } from 'next/cache';
async function handleWebhook(payload: any) {
// پردازش محتوای وبهوک
// بیاعتبار کردن کش برای دادههای مرتبط
revalidateTag("products");
revalidateTag(`product:${payload.productId}`);
}
نکته کلی: از اعتبارسنجی مجدد دستی به صورت استراتژیک استفاده کنید. بیاعتبار کردن بیش از حد میتواند مزایای کشینگ را از بین ببرد، در حالی که بیاعتبار کردن کمتر از حد میتواند منجر به دادههای کهنه شود.
موارد استفاده عملی برای `unstable_cache`
۱. محتوای پویا با بهروزرسانیهای نادر
برای وبسایتهایی با محتوای پویا که خیلی زیاد تغییر نمیکند (مانند پستهای وبلاگ، مقالات خبری)، میتوانید از unstable_cache
با TTL طولانیتر برای کش کردن دادهها برای دورههای طولانی استفاده کنید. این کار بار روی بکاند شما را کاهش داده و زمان بارگذاری صفحه را بهبود میبخشد.
۲. دادههای مختص کاربر
برای دادههای مختص کاربر (مانند پروفایلهای کاربری، سبدهای خرید)، میتوانید از unstable_cache
با کلیدهای کش که شامل شناسه کاربر است، استفاده کنید. این تضمین میکند که هر کاربر دادههای خود را میبیند و کش هنگام تغییر دادههای کاربر بیاعتبار میشود.
۳. دادههای لحظهای با تحمل دادههای کهنه
برای برنامههایی که دادههای لحظهای نمایش میدهند (مانند قیمت سهام، فیدهای شبکههای اجتماعی)، میتوانید از unstable_cache
با TTL کوتاه برای ارائه بهروزرسانیهای تقریباً لحظهای استفاده کنید. این کار تعادلی بین نیاز به دادههای بهروز و مزایای عملکردی کشینگ برقرار میکند.
۴. تست A/B
در طول تست A/B، مهم است که نسخه آزمایشی اختصاص داده شده به کاربر را کش کنید تا تجربه ثابتی تضمین شود. `unstable_cache` میتواند برای کش کردن نسخه انتخاب شده با استفاده از شناسه کاربر به عنوان بخشی از کلید کش استفاده شود.
مزایای استفاده از `unstable_cache`
- بهبود عملکرد: با کش کردن دادهها،
unstable_cache
بار روی بکاند شما را کاهش داده و زمان بارگذاری صفحه را بهبود میبخشد. - کاهش هزینههای بکاند: کشینگ تعداد درخواستها به بکاند شما را کاهش میدهد، که میتواند هزینههای زیرساختی شما را کاهش دهد.
- تجربه کاربری بهبود یافته: زمان بارگذاری سریعتر صفحه و تعاملات روانتر منجر به تجربه کاربری بهتر میشود.
- کنترل دقیق:
unstable_cache
کنترل دقیقی بر رفتار کشینگ فراهم میکند و به شما امکان میدهد آن را متناسب با نیازهای خاص برنامه خود تنظیم کنید.
ملاحظات و بهترین شیوهها
- استراتژی بیاعتبار کردن کش: یک استراتژی بیاعتبار کردن کش کاملاً تعریف شده ایجاد کنید تا اطمینان حاصل شود که کش شما هنگام تغییر دادهها بهروز میشود.
- انتخاب TTL: مقادیر TTL مناسب را بر اساس فرکانس بهروزرسانی دادهها و حساسیت برنامه شما به دادههای کهنه انتخاب کنید.
- طراحی کلید کش: کلیدهای کش خود را با دقت طراحی کنید تا اطمینان حاصل شود که منحصر به فرد و سازگار هستند.
- نظارت و ثبت وقایع: عملکرد کش خود را نظارت کرده و برخوردها (hits) و عدم برخوردها (misses) را ثبت کنید تا مشکلات احتمالی را شناسایی کنید.
- کشینگ لبه در مقابل کشینگ مرورگر: تفاوتهای بین کشینگ لبه (CDN) و کشینگ مرورگر را در نظر بگیرید. کشینگ لبه بین همه کاربران به اشتراک گذاشته میشود، در حالی که کشینگ مرورگر مختص هر کاربر است. استراتژی کشینگ مناسب را بر اساس نوع داده و نیازهای برنامه خود انتخاب کنید.
- مدیریت خطا: مدیریت خطای قوی را برای رسیدگی به عدم برخوردهای کش و جلوگیری از انتقال خطاها به کاربر پیادهسازی کنید. استفاده از یک مکانیسم جایگزین (fallback) برای بازیابی دادهها از بکاند در صورت در دسترس نبودن کش را در نظر بگیرید.
- تست: پیادهسازی کشینگ خود را به طور کامل تست کنید تا اطمینان حاصل شود که مطابق انتظار کار میکند. از تستهای خودکار برای تأیید منطق بیاعتبار کردن و اعتبارسنجی مجدد کش استفاده کنید.
مقایسه `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 را در آغوش بگیرید و پتانسیل کامل برنامههای وب خود را آزاد کنید.