بررسی کنید که چگونه سرویس ورکرها درخواستهای بارگذاری صفحه را رهگیری کرده و استراتژیهای کشینگ، عملکرد آفلاین و بهبود کارایی را برای برنامههای وب مدرن فراهم میکنند.
ناوبری سرویس ورکر فرانتاند: رهگیری بارگذاری صفحات برای بهبود تجربه کاربری
سرویس ورکرها یک فناوری قدرتمند هستند که به شما امکان میدهند درخواستهای شبکه را رهگیری کنید، منابع را کش کنید و قابلیت آفلاین را برای برنامههای وب فراهم کنید. یکی از تأثیرگذارترین قابلیتها، رهگیری درخواستهای بارگذاری صفحه است که به شما اجازه میدهد به طور چشمگیری عملکرد و تجربه کاربری را بهبود بخشید. این پست به بررسی چگونگی مدیریت درخواستهای ناوبری توسط سرویس ورکرها میپردازد و مثالهای عملی و بینشهای کاربردی را برای توسعهدهندگان ارائه میدهد.
درک درخواستهای ناوبری
قبل از پرداختن به کد، بیایید تعریف کنیم که «درخواست ناوبری» در زمینه سرویس ورکرها چیست. درخواست ناوبری، درخواستی است که توسط کاربر هنگام رفتن به یک صفحه جدید یا تازهسازی صفحه فعلی آغاز میشود. این درخواستها معمولاً توسط موارد زیر فعال میشوند:
- کلیک کردن روی یک لینک (تگ
<a>) - تایپ کردن یک URL در نوار آدرس
- تازهسازی صفحه
- استفاده از دکمههای بازگشت یا جلو در مرورگر
سرویس ورکرها توانایی رهگیری این درخواستهای ناوبری و تعیین نحوه مدیریت آنها را دارند. این امر امکان پیادهسازی استراتژیهای کشینگ پیچیده، ارائه محتوا از کش هنگام آفلاین بودن کاربر و حتی تولید پویای صفحات در سمت کلاینت را فراهم میکند.
ثبت کردن یک سرویس ورکر
اولین قدم، ثبت کردن یک سرویس ورکر است. این کار معمولاً در فایل اصلی جاوا اسکریپت شما انجام میشود:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
این کد بررسی میکند که آیا مرورگر از سرویس ورکرها پشتیبانی میکند یا خیر و در صورت پشتیبانی، فایل /service-worker.js را ثبت میکند. اطمینان حاصل کنید که این جاوا اسکریپت در یک زمینه امن (HTTPS) برای محیطهای تولیدی اجرا شود.
رهگیری درخواستهای ناوبری در سرویس ورکر
درون فایل service-worker.js خود، میتوانید به رویداد fetch گوش دهید. این رویداد برای هر درخواست شبکهای که توسط برنامه شما انجام میشود، از جمله درخواستهای ناوبری، فعال میشود. ما میتوانیم این درخواستها را فیلتر کنیم تا به طور خاص درخواستهای ناوبری را مدیریت کنیم.
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(async () => {
try {
// First, try to use the navigation preload response if it's supported.
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// Always try the network first.
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
// catch is only triggered if an exception is thrown, which is likely
// due to a network error.
// If fetching the HTML file fails, look for a fallback.
console.log('Fetch failed; returning offline page instead.', error);
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(OFFLINE_URL);
return cachedResponse || createErrorResponse(); // Fallback if offline page unavailable
}
});
}
});
بیایید این کد را تجزیه کنیم:
event.request.mode === 'navigate': این شرط بررسی میکند که آیا درخواست یک درخواست ناوبری است یا خیر.event.respondWith(): این متد به مرورگر میگوید که چگونه درخواست را مدیریت کند. این متد یک promise میگیرد که به یک شیءResponseحل میشود.event.preloadResponse: این یک مکانیزم به نام Navigation Preload است. اگر فعال باشد، به مرورگر اجازه میدهد تا قبل از فعال شدن کامل سرویس ورکر، شروع به واکشی درخواست ناوبری کند. این کار با همپوشانی زمان راهاندازی سرویس ورکر با درخواست شبکه، باعث بهبود سرعت میشود.fetch(event.request): این منبع را از شبکه واکشی میکند. اگر شبکه در دسترس باشد، صفحه به طور معمول از سرور بارگذاری میشود.caches.open(CACHE_NAME): این یک کش با نام مشخص شده باز میکند (CACHE_NAMEباید در جای دیگری از فایل سرویس ورکر شما تعریف شود).cache.match(OFFLINE_URL): این به دنبال یک پاسخ کش شده میگردد که باOFFLINE_URLمطابقت داشته باشد (مثلاً یک صفحه آفلاین).createErrorResponse(): این یک تابع سفارشی است که یک پاسخ خطا برمیگرداند. شما میتوانید این تابع را برای ارائه یک تجربه آفلاین کاربرپسند سفارشی کنید.
استراتژیهای کشینگ برای درخواستهای ناوبری
مثال قبلی یک استراتژی ابتدایی اول-شبکه را نشان میدهد. با این حال، شما میتوانید بسته به نیازمندیهای برنامه خود، استراتژیهای کشینگ پیچیدهتری را پیادهسازی کنید.
اول شبکه، در صورت شکست بازگشت به کش
این همان استراتژی نشان داده شده در مثال قبلی است. ابتدا تلاش میکند منبع را از شبکه واکشی کند. اگر درخواست شبکه شکست بخورد (مثلاً کاربر آفلاین باشد)، به کش باز میگردد. این یک استراتژی خوب برای محتوایی است که به طور مکرر بهروزرسانی میشود.
اول کش، بهروزرسانی در پسزمینه
این استراتژی ابتدا کش را بررسی میکند. اگر منبع در کش پیدا شود، بلافاصله برگردانده میشود. در پسزمینه، سرویس ورکر کش را با آخرین نسخه منبع از شبکه بهروزرسانی میکند. این امر یک بارگذاری اولیه سریع را فراهم میکند و تضمین میکند که کاربر در نهایت همیشه جدیدترین محتوا را خواهد داشت.
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
if (cachedResponse) {
// Update the cache in the background.
event.waitUntil(
fetch(event.request).then(response => {
return caches.open(CACHE_NAME).then(cache => {
return cache.put(event.request, response.clone());
});
})
);
return cachedResponse;
}
// If not found in cache, fetch from network.
return fetch(event.request);
})
);
}
});
فقط کش
این استراتژی فقط محتوا را از کش ارائه میدهد. اگر منبع در کش پیدا نشود، درخواست با شکست مواجه میشود. این برای داراییهایی مناسب است که به عنوان استاتیک و در دسترس به صورت آفلاین شناخته میشوند.
کهنه-هنگام-اعتبارسنجی-مجدد (Stale-While-Revalidate)
مشابه اول-کش، اما به جای بهروزرسانی در پسزمینه با event.waitUntil، شما بلافاصله پاسخ کش شده را برمیگردانید (در صورت وجود) و *همیشه* تلاش میکنید آخرین نسخه را از شبکه واکشی کرده و کش را بهروزرسانی کنید. این رویکرد یک بارگذاری اولیه بسیار سریع را فراهم میکند، زیرا کاربر نسخه کش شده را فوراً دریافت میکند، اما تضمین میکند که کش در نهایت با تازهترین دادهها بهروز خواهد شد و برای درخواست بعدی آماده خواهد بود. این برای منابع غیرحیاتی یا شرایطی که نمایش اطلاعات کمی قدیمی برای مدت کوتاه در ازای سرعت قابل قبول است، عالی است.
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(
caches.open(CACHE_NAME).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 the cached response if we have it, otherwise wait
// for the network.
return cachedResponse || fetchedResponse;
});
})
);
}
});
پیشبارگذاری ناوبری (Navigation Preload)
پیشبارگذاری ناوبری یک ویژگی است که به مرورگر اجازه میدهد قبل از فعال شدن کامل سرویس ورکر، شروع به واکشی منبع کند. این میتواند به طور قابل توجهی عملکرد درخواستهای ناوبری را بهبود بخشد، به خصوص در اولین بازدید از سایت شما.
برای فعال کردن پیشبارگذاری ناوبری، شما باید:
- آن را در رویداد
activateسرویس ورکر خود فعال کنید. - در رویداد
fetchبه دنبالpreloadResponseبگردید.
// In the activate event:
self.addEventListener('activate', event => {
event.waitUntil(self.registration.navigationPreload.enable());
});
// In the fetch event (as shown in the initial example):
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(async () => {
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// ... rest of your fetch logic ...
});
}
});
مدیریت سناریوهای آفلاین
یکی از مزایای اصلی استفاده از سرویس ورکرها، قابلیت ارائه عملکرد آفلاین است. هنگامی که کاربر آفلاین است، میتوانید نسخه کش شدهای از برنامه خود را ارائه دهید یا یک صفحه آفلاین سفارشی نمایش دهید.
برای مدیریت سناریوهای آفلاین، شما باید:
- داراییهای لازم، از جمله HTML، CSS، جاوا اسکریپت و تصاویر خود را کش کنید.
- در رویداد
fetch، هرگونه خطای شبکه را گرفته و یک صفحه آفلاین کش شده را ارائه دهید.
// Define the offline page URL and cache name
const OFFLINE_URL = '/offline.html';
const CACHE_NAME = 'my-app-cache-v1';
// Install event: cache static assets
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll([
'/',
'/index.html',
'/style.css',
'/app.js',
OFFLINE_URL // Cache the offline page
]);
})
);
self.skipWaiting(); // Immediately activate the service worker
});
// Fetch event: handle navigation requests and offline fallback
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(async () => {
try {
// First, try to use the navigation preload response if it's supported.
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// Always try the network first.
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
// catch is only triggered if an exception is thrown, which is likely
// due to a network error.
// If fetching the HTML file fails, look for a fallback.
console.log('Fetch failed; returning offline page instead.', error);
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(OFFLINE_URL);
return cachedResponse || createErrorResponse(); // Fallback if offline page unavailable
}
});
}
});
function createErrorResponse() {
return new Response(
`Offline
You are currently offline. Please check your internet connection.
`, {
headers: { 'Content-Type': 'text/html' }
}
);
}
این کد یک صفحه offline.html را در حین رویداد install کش میکند. سپس، در رویداد fetch، اگر درخواست شبکه با شکست مواجه شود (بلوک catch اجرا میشود)، کش را برای صفحه offline.html بررسی کرده و آن را به مرورگر برمیگرداند.
تکنیکها و ملاحظات پیشرفته
استفاده مستقیم از Cache Storage API
شیء caches یک API قدرتمند برای مدیریت پاسخهای کش شده فراهم میکند. شما میتوانید از متدهایی مانند cache.put()، cache.match() و cache.delete() برای دستکاری مستقیم کش استفاده کنید. این به شما کنترل دقیقی بر نحوه کش شدن و بازیابی منابع میدهد.
کشینگ پویا
علاوه بر کش کردن داراییهای استاتیک، شما میتوانید محتوای پویا مانند پاسخهای API را نیز کش کنید. این میتواند به طور قابل توجهی عملکرد برنامه شما را بهبود بخشد، به خصوص برای کاربرانی که اتصال اینترنت کند یا نامطمئن دارند.
نسخهبندی کش
نسخهبندی کش شما مهم است تا بتوانید منابع کش شده را هنگام تغییر برنامه خود بهروزرسانی کنید. یک رویکرد رایج این است که یک شماره نسخه را در CACHE_NAME قرار دهید. هنگامی که برنامه خود را بهروز میکنید، میتوانید شماره نسخه را افزایش دهید، که این کار مرورگر را مجبور به دانلود منابع جدید میکند.
const CACHE_NAME = 'my-app-cache-v2'; // Increment the version number
شما همچنین باید کشهای قدیمی را حذف کنید تا از انباشته شدن و هدر رفتن فضای ذخیرهسازی جلوگیری کنید. میتوانید این کار را در رویداد activate انجام دهید.
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
همگامسازی پسزمینه (Background Sync)
سرویس ورکرها همچنین Background Sync API را فراهم میکنند، که به شما اجازه میدهد وظایف را تا زمانی که کاربر اتصال اینترنت پایداری داشته باشد به تعویق بیندازید. این برای سناریوهایی مانند ارسال فرمها یا آپلود فایلها زمانی که کاربر آفلاین است، مفید است.
اعلانهای پوش (Push Notifications)
سرویس ورکرها همچنین میتوانند برای پیادهسازی اعلانهای پوش استفاده شوند، که به شما اجازه میدهد حتی زمانی که کاربران به طور فعال از برنامه شما استفاده نمیکنند، برای آنها پیام ارسال کنید. این میتواند برای اطلاعرسانی به کاربران در مورد محتوای جدید، بهروزرسانیها یا رویدادهای مهم استفاده شود.
ملاحظات بینالمللیسازی (i18n) و محلیسازی (L10n)
هنگام پیادهسازی سرویس ورکرها در یک برنامه جهانی، در نظر گرفتن بینالمللیسازی (i18n) و محلیسازی (L10n) بسیار مهم است. در اینجا چند جنبه کلیدی آورده شده است:
- تشخیص زبان: یک مکانیزم برای تشخیص زبان ترجیحی کاربر پیادهسازی کنید. این میتواند شامل استفاده از هدر HTTP
Accept-Language، تنظیمات کاربر یا APIهای مرورگر باشد. - محتوای محلیسازی شده: نسخههای محلیسازی شده صفحات آفلاین و سایر محتوای کش شده خود را ذخیره کنید. از زبان تشخیص داده شده برای ارائه نسخه مناسب استفاده کنید. به عنوان مثال، میتوانید صفحات آفلاین جداگانهای برای انگلیسی (
/offline.en.html)، اسپانیایی (/offline.es.html) و فرانسوی (/offline.fr.html) داشته باشید. سپس سرویس ورکر شما فایل صحیح را برای کش کردن و ارائه بر اساس زبان کاربر به صورت پویا انتخاب میکند. - قالببندی تاریخ و زمان: اطمینان حاصل کنید که هر تاریخ و زمانی که در صفحات آفلاین شما نمایش داده میشود، مطابق با منطقه کاربر قالببندی شده است. برای این منظور از API
Intlجاوا اسکریپت استفاده کنید. - قالببندی ارز: اگر برنامه شما مقادیر ارزی را نمایش میدهد، آنها را مطابق با منطقه و ارز کاربر قالببندی کنید. باز هم، از API
Intlبرای قالببندی ارز استفاده کنید. - جهت متن: زبانهایی را که از راست به چپ (RTL) خوانده میشوند، مانند عربی و عبری، در نظر بگیرید. صفحات آفلاین و محتوای کش شده شما باید با استفاده از CSS از جهت متن RTL پشتیبانی کنند.
- بارگذاری منابع: منابع محلیسازی شده (مانند تصاویر، فونتها) را به صورت پویا بر اساس زبان کاربر بارگذاری کنید.
مثال: انتخاب صفحه آفلاین محلیسازی شده
// Function to get the user's preferred language
function getPreferredLanguage() {
// This is a simplified example. In a real application,
// you would use a more robust language detection mechanism.
return navigator.language || navigator.userLanguage || 'en';
}
// Define a mapping of languages to offline page URLs
const offlinePageUrls = {
'en': '/offline.en.html',
'es': '/offline.es.html',
'fr': '/offline.fr.html'
};
// Get the user's preferred language
const preferredLanguage = getPreferredLanguage();
// Determine the offline page URL based on the preferred language
let offlineUrl = offlinePageUrls[preferredLanguage] || offlinePageUrls['en']; // Default to English if no match
// ... rest of your service worker code, using offlineUrl to cache and serve the appropriate offline page ...
تست و اشکالزدایی
تست و اشکالزدایی سرویس ورکرها میتواند چالشبرانگیز باشد. در اینجا چند نکته آورده شده است:
- از Chrome DevTools استفاده کنید: ابزارهای توسعهدهنده کروم یک پنل اختصاصی برای بازرسی سرویس ورکرها فراهم میکند. میتوانید از این پنل برای مشاهده وضعیت سرویس ورکر خود، بازرسی منابع کش شده و اشکالزدایی درخواستهای شبکه استفاده کنید.
- از "Update on reload" سرویس ورکر استفاده کنید: در Chrome DevTools -> Application -> Service Workers، میتوانید گزینه "Update on reload" را علامت بزنید تا سرویس ورکر در هر بار بارگذاری مجدد صفحه مجبور به بهروزرسانی شود. این در طول توسعه بسیار مفید است.
- پاک کردن حافظه: گاهی اوقات، سرویس ورکر ممکن است در وضعیت بدی قرار گیرد. پاک کردن حافظه مرورگر (شامل کش) میتواند به حل این مشکلات کمک کند.
- از یک کتابخانه تست سرویس ورکر استفاده کنید: چندین کتابخانه مانند Workbox موجود است که میتواند به شما در تست سرویس ورکرها کمک کند.
- روی دستگاههای واقعی تست کنید: در حالی که میتوانید سرویس ورکرها را در یک مرورگر دسکتاپ تست کنید، مهم است که روی دستگاههای تلفن همراه واقعی نیز تست کنید تا اطمینان حاصل شود که آنها در شرایط مختلف شبکه به درستی کار میکنند.
نتیجهگیری
رهگیری درخواستهای بارگذاری صفحه با سرویس ورکرها یک تکنیک قدرتمند برای بهبود تجربه کاربری برنامههای وب است. با پیادهسازی استراتژیهای کشینگ، ارائه عملکرد آفلاین و بهینهسازی درخواستهای شبکه، میتوانید به طور قابل توجهی عملکرد و تعامل را بهبود بخشید. به یاد داشته باشید که هنگام توسعه برای مخاطبان جهانی، بینالمللیسازی را در نظر بگیرید تا تجربهای یکنواخت و کاربرپسند برای همه تضمین شود.
این راهنما یک پایه محکم برای درک و پیادهسازی رهگیری ناوبری سرویس ورکر فراهم میکند. با ادامه کاوش در این فناوری، راههای بیشتری برای بهرهبرداری از قابلیتهای آن برای ایجاد تجربیات وب استثنایی کشف خواهید کرد.