تا به حال، تنها اشارهها و کدهای کوچکی از رابط Cache
وجود داشته است. برای استفاده مؤثر از سرویسکارها، لازم است یک یا چند استراتژی ذخیرهسازی را اتخاذ کنید که نیاز به کمی آشنایی با رابط Cache
دارد.
استراتژی ذخیره سازی یک تعامل بین رویداد fetch
یک سرویس دهنده و رابط Cache
است. نحوه نگارش یک استراتژی کش بستگی دارد. برای مثال، ممکن است ترجیح داده شود که درخواستها برای داراییهای استاتیک متفاوت از اسناد رسیدگی شود، و این بر نحوه ترکیب استراتژی ذخیرهسازی تأثیر میگذارد.
قبل از اینکه به خود استراتژیها بپردازیم، اجازه دهید لحظهای در مورد اینکه رابط Cache
نیست، چیست و خلاصهای از روشهایی که برای مدیریت کشهای سرویسکار ارائه میدهد صحبت کنیم.
رابط Cache
در مقابل کش HTTP
اگر قبلاً با رابط Cache
کار نکرده اید، ممکن است وسوسه انگیز باشد که آن را مانند حافظه پنهان HTTP یا حداقل مرتبط با آن در نظر بگیرید. اینطور نیست.
- رابط
Cache
یک مکانیسم کش است که کاملاً جدا از کش HTTP است. - از هر پیکربندی
Cache-Control
که برای تأثیرگذاری بر حافظه نهان HTTP استفاده میکنید، تأثیری روی داراییهایی که درCache
ذخیره میشوند، ندارد.
این کمک می کند که حافظه پنهان مرورگر را لایه لایه در نظر بگیرید. حافظه پنهان HTTP یک حافظه پنهان سطح پایین است که توسط جفتهای کلید-مقدار با دستورالعملهای بیان شده در هدرهای HTTP هدایت میشود.
در مقابل، رابط Cache
یک کش سطح بالا است که توسط یک JavaScript API هدایت می شود. این انعطاف پذیری بیشتری نسبت به استفاده از جفت های کلید-مقدار HTTP نسبتاً ساده ارائه می دهد و نیمی از چیزی است که استراتژی های کش را ممکن می کند. برخی از روشهای مهم API در مورد کشهای سرویسکار عبارتند از:
-
CacheStorage.open
برای ایجاد یک نمونهCache
جدید. -
Cache.add
وCache.put
برای ذخیره پاسخ های شبکه در کش سرویس کارمند. -
Cache.match
برای یافتن پاسخ ذخیره شده در حافظه پنهان در یک نمونهCache
. -
Cache.delete
برای حذف یک پاسخ ذخیره شده از یک نمونهCache
.
اینها فقط تعدادی هستند. روشهای مفید دیگری نیز وجود دارد، اما اینها روشهای اساسی هستند که در ادامه در این راهنما خواهید دید.
رویداد واکشی fetch
نیمه دیگر استراتژی ذخیره سازی، رویداد fetch
کارگر سرویس است. تاکنون در این مستندات، مقداری در مورد «شنود درخواستهای شبکه» شنیدهاید، و رویداد fetch
در داخل یک سرویسکار جایی است که این اتفاق میافتد:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(cacheName));
});
self.addEventListener('fetch', async (event) => {
// Is this a request for an image?
if (event.request.destination === 'image') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Respond with the image from the cache or from the network
return cache.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
// Add the network response to the cache for future visits.
// Note: we need to make a copy of the response to save it in
// the cache and use the original as the request response.
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
این یک نمونه اسباببازی است - و شما میتوانید آن را در عمل ببینید - اما نمونهای است که نگاهی اجمالی به کارهایی که کارگران خدمات میتوانند انجام دهند را ارائه میدهد. کد بالا کارهای زیر را انجام می دهد:
- ویژگی
destination
درخواست را بررسی کنید تا ببینید آیا این یک درخواست تصویری است یا خیر. - اگر تصویر در کش سرویس کارگر است، آن را از آنجا سرو کنید. اگر نه، تصویر را از شبکه واکشی کنید، پاسخ را در حافظه پنهان ذخیره کنید و پاسخ شبکه را برگردانید.
- تمام درخواستهای دیگر بدون هیچ تعاملی با حافظه پنهان از طریق سرویسکار ارسال میشوند.
شی event
واکشی حاوی یک ویژگی request
است که چند بیت اطلاعات مفید برای کمک به شناسایی نوع هر درخواست دارد:
-
url
، که URL درخواست شبکه است که در حال حاضر توسط رویدادfetch
مدیریت می شود. -
method
، که روش درخواست است (به عنوان مثال،GET
یاPOST
). -
mode
، که حالت درخواست را توصیف می کند. مقدار'navigate'
اغلب برای تمایز درخواست برای اسناد HTML از سایر درخواست ها استفاده می شود. -
destination
، که نوع محتوای درخواست شده را به گونه ای توصیف می کند که از استفاده از پسوند فایل دارایی درخواستی جلوگیری می کند.
یک بار دیگر، نام بازی Asynchrony است. به خاطر می آورید که رویداد install
یک روش event.waitUntil
ارائه می دهد که یک قول را می گیرد و قبل از ادامه فعال سازی منتظر می ماند تا حل شود. رویداد fetch
روش event.respondWith
مشابهی را ارائه میکند که میتوانید از آن برای بازگرداندن نتیجه درخواست fetch
ناهمزمان یا پاسخی که توسط روش match
رابط Cache
بازگردانده شده است استفاده کنید.
استراتژی های ذخیره سازی
اکنون که کمی با نمونه های Cache
و کنترل کننده رویداد fetch
آشنایی دارید، آماده هستید تا به برخی از استراتژی های ذخیره سازی کش توسط سرویس دهنده بپردازید. در حالی که احتمالات عملا بی پایان هستند، این راهنما با استراتژی هایی که با Workbox ارائه می شود، همراه است، بنابراین می توانید درک کنید که در قسمت داخلی Workbox چه می گذرد.
فقط کش
بیایید با یک استراتژی ذخیره سازی ساده شروع کنیم که آن را «فقط کش» می نامیم. فقط این است که: وقتی سرویسکار صفحه را کنترل میکند، درخواستهای تطبیق فقط به حافظه پنهان میروند. این بدان معناست که هر دارایی ذخیره شده در حافظه پنهان باید از پیش ذخیره شود تا بتواند الگو را کار کند و این دارایی ها هرگز در حافظه پنهان به روز نمی شوند تا زمانی که سرویس دهنده به روز شود.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
// Assets to precache
const precachedAssets = [
'/possum1.jpg',
'/possum2.jpg',
'/possum3.jpg',
'/possum4.jpg'
];
self.addEventListener('install', (event) => {
// Precache assets on install
event.waitUntil(caches.open(cacheName).then((cache) => {
return cache.addAll(precachedAssets);
}));
});
self.addEventListener('fetch', (event) => {
// Is this one of our precached assets?
const url = new URL(event.request.url);
const isPrecachedRequest = precachedAssets.includes(url.pathname);
if (isPrecachedRequest) {
// Grab the precached asset from the cache
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request.url);
}));
} else {
// Go to the network
return;
}
});
در بالا، آرایه ای از دارایی ها در زمان نصب از قبل ذخیره می شوند. هنگامی که سرویسکار واکشیها را مدیریت میکند، بررسی میکنیم که آیا URL درخواستی که توسط رویداد fetch
انجام میشود در آرایه داراییهای از پیش ذخیرهشده قرار دارد یا خیر. اگر چنین است، منبع را از حافظه پنهان می گیریم و از شبکه می گذریم. سایر درخواستها به شبکه و فقط شبکه منتقل میشوند. برای مشاهده عملی این استراتژی، این نسخه نمایشی را با کنسول خود باز کنید .
فقط شبکه
نقطه مقابل "تنها حافظه پنهان" "فقط شبکه" است، که در آن یک درخواست از طریق یک سرویس دهنده بدون هیچ گونه تعاملی با کش سرویس دهنده به شبکه ارسال می شود. این یک استراتژی خوب برای حصول اطمینان از تازگی محتوا است (مارک آپ فکری)، اما نتیجه آن این است که وقتی کاربر آفلاین است هرگز کار نخواهد کرد.
اطمینان از ارسال درخواست به شبکه فقط به این معنی است که event.respondWith
برای یک درخواست منطبق تماس نمیگیرید. اگر میخواهید صریح باشید، میتوانید یک return;
در fetch
رویداد پاسخ به تماس شما برای درخواست هایی که می خواهید به شبکه ارسال کنید. این چیزی است که در نسخه ی نمایشی استراتژی "Cache Only" برای درخواست هایی که از قبل ذخیره نشده اند اتفاق می افتد.
ابتدا حافظه پنهان، بازگشت به شبکه
این استراتژی جایی است که همه چیز کمی بیشتر درگیر می شود. برای تطبیق درخواست ها، روند به این صورت است:
- درخواست به حافظه پنهان برخورد می کند. اگر دارایی در حافظه پنهان است، آن را از آنجا سرو کنید.
- اگر درخواست در کش نیست ، به شبکه بروید.
- پس از اتمام درخواست شبکه، آن را به حافظه پنهان اضافه کنید، سپس پاسخ را از شبکه برگردانید.
در اینجا یک نمونه از این استراتژی است که می توانید آن را در یک نسخه آزمایشی زنده آزمایش کنید:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a request for an image
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the cache first
return cache.match(event.request.url).then((cachedResponse) => {
// Return a cached response if we have one
if (cachedResponse) {
return cachedResponse;
}
// Otherwise, hit the network
return fetch(event.request).then((fetchedResponse) => {
// Add the network response to the cache for later visits
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
اگرچه این مثال فقط تصاویر را پوشش میدهد، این یک استراتژی عالی برای اعمال بر روی تمام داراییهای ثابت (مانند CSS، جاوا اسکریپت، تصاویر و فونتها) بهویژه موارد دارای نسخه هش است. با کنار گذاشتن هر گونه بررسی تازگی محتوا با سروری که حافظه پنهان HTTP ممکن است راه اندازی شود، سرعت دارایی های تغییرناپذیر را افزایش می دهد. مهمتر از آن، هر دارایی ذخیره شده به صورت آفلاین در دسترس خواهد بود.
ابتدا شبکه، بازگشت به حافظه پنهان
اگر بخواهید «اول حافظه پنهان، دوم شبکه» را روی سر آن بچرخانید، در نهایت با استراتژی «اول شبکه، دوم حافظه پنهان» مواجه می شوید که به نظر می رسد:
- ابتدا برای درخواست به شبکه می روید و پاسخ را در حافظه پنهان قرار می دهید.
- اگر بعداً آفلاین باشید، به آخرین نسخه آن پاسخ در حافظه پنهان باز میگردید.
این استراتژی برای درخواستهای HTML یا API زمانی عالی است که وقتی آنلاین هستید، آخرین نسخه یک منبع را میخواهید، اما میخواهید به آخرین نسخه موجود دسترسی آفلاین بدهید. زمانی که در درخواستهای HTML اعمال میشود، به این صورت است:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a navigation request
if (event.request.mode === 'navigate') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the network first
return fetch(event.request.url).then((fetchedResponse) => {
cache.put(event.request, fetchedResponse.clone());
return fetchedResponse;
}).catch(() => {
// If the network is unavailable, get
return cache.match(event.request.url);
});
}));
} else {
return;
}
});
می توانید این را در یک نسخه نمایشی امتحان کنید. ابتدا به صفحه بروید. ممکن است لازم باشد قبل از قرار دادن پاسخ HTML در حافظه پنهان، مجدداً بارگیری کنید. سپس در ابزارهای توسعه دهنده خود، یک اتصال آفلاین را شبیه سازی کنید و دوباره بارگیری کنید. آخرین نسخه موجود فوراً از حافظه پنهان ارائه می شود.
در شرایطی که قابلیت آفلاین مهم است، اما باید بین این قابلیت و دسترسی به جدیدترین نسخه کمی از نشانهگذاری یا دادههای API تعادل برقرار کنید، «اول شبکه، دوم حافظه پنهان» یک استراتژی محکم است که به آن هدف میرسد.
قدیمی-در حالی که-تأیید مجدد
از میان استراتژیهایی که تا به حال به آن پرداختهایم، «Stale-while-Revalidate» پیچیدهترین است. از برخی جهات شبیه به دو استراتژی آخر است، اما این رویه سرعت دسترسی به یک منبع را در اولویت قرار می دهد، در حالی که آن را در پس زمینه به روز نگه می دارد. این استراتژی چیزی شبیه به این است:
- در اولین درخواست برای یک دارایی، آن را از شبکه واکشی کنید، آن را در حافظه پنهان قرار دهید و پاسخ شبکه را برگردانید.
- در درخواستهای بعدی، ابتدا دارایی را از حافظه پنهان ارائه دهید، سپس در پسزمینه، آن را مجدداً از شبکه درخواست کنید و ورودی حافظه پنهان دارایی را بهروزرسانی کنید.
- برای درخواست های پس از آن، آخرین نسخه واکشی شده از شبکه را که در مرحله قبل در حافظه پنهان قرار داده شده بود، دریافت خواهید کرد.
این یک استراتژی عالی برای چیزهایی است که برای به روز نگه داشتن آنها بسیار مهم است، اما حیاتی نیستند. به چیزهایی مانند آواتار برای یک سایت رسانه اجتماعی فکر کنید. هنگامی که کاربران به انجام این کار نزدیک می شوند، آنها به روز می شوند، اما آخرین نسخه برای هر درخواستی کاملاً ضروری نیست.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request).then((cachedResponse) => {
const fetchedResponse = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchedResponse;
});
}));
} else {
return;
}
});
شما می توانید این را در یک نسخه آزمایشی زنده دیگر مشاهده کنید، به خصوص اگر به برگه شبکه در ابزارهای توسعه دهنده مرورگر خود و نمایشگر CacheStorage
آن توجه کنید (اگر ابزارهای توسعه دهنده مرورگر شما چنین ابزاری دارند).
پیش به سمت Workbox!
این سند بررسی ما را در مورد API کارگران سرویس و همچنین APIهای مرتبط به پایان میرساند، به این معنی که شما به اندازه کافی در مورد نحوه استفاده مستقیم از کارکنان خدمات برای شروع کار با Workbox یاد گرفتهاید!