مقدمه

Service Worker قدرتمندترین و پیچیده‌ترین نوع Worker است که یک تغییر پارادایم در نحوه عملکرد وب اپلیکیشن‌ها ایجاد می‌کند. یک Service Worker در واقع یک پراکسی شبکه قابل برنامه‌نویسی است که بین اپلیکیشن شما، مرورگر و شبکه قرار می‌گیرد. این قابلیت به ما اجازه می‌دهد تا درخواست‌های شبکه را رهگیری کرده، پاسخ‌ها را مدیریت کنیم و یک کنترل دقیق بر روی منابع و داده‌ها داشته باشیم.

Service Workerها سنگ بنای اصلی «اپلیکیشن‌های وب پیش‌رونده» یا Progressive Web Apps (PWA) هستند و قابلیت‌های کلیدی زیر را فعال می‌کنند:

  • قابلیت کار آفلاین: با کش کردن منابع، می‌توان اپلیکیشن را طوری طراحی کرد که حتی بدون اتصال به اینترنت نیز کار کند.
  • اعلان‌های فشاری (Push Notifications): دریافت و نمایش اعلان‌ها از سرور، حتی زمانی که صفحه وب بسته است.
  • همگام‌سازی در پس‌زمینه (Background Sync): انجام عملیاتی مانند ارسال داده‌های یک فرم، پس از برقراری مجدد اتصال به اینترنت.

Service Workerها دارای یک چرخه حیات مستقل از صفحه وب هستند و به دلایل امنیتی، فقط روی بسترهای امن (HTTPS) کار می‌کنند.

چرخه حیات یک Service Worker

درک چرخه حیات یک Service Worker برای کار با آن ضروری است. این چرخه شامل سه مرحله اصلی است: ثبت‌نام، نصب و فعال‌سازی.

۱. ثبت نام (Registration)

اولین قدم، ثبت کردن اسکریپت Service Worker از صفحه اصلی وب‌سایت است. این کار معمولاً در رویداد load صفحه انجام می‌شود تا با بارگذاری اولیه تداخل نداشته باشد.

Copy Icon JAVASCRIPT - main.js
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
            .then(registration => {
                console.log('ServiceWorker registration successful with scope: ', registration.scope);
            })
            .catch(err => {
                console.error('ServiceWorker registration failed: ', err);
            });
    });
}

این کد ابتدا بررسی می‌کند که آیا مرورگر از Service Worker پشتیبانی می‌کند یا خیر. سپس اقدام به ثبت فایل sw.js به عنوان Service Worker می‌کند.

۲. نصب (Installation)

پس از ثبت موفق، مرورگر فایل اسکریپت Service Worker را دانلود و اجرا می‌کند و رویداد install در داخل آن اجرا می‌شود. این مرحله تنها یک بار برای هر نسخه از Service Worker اتفاق می‌افتد و بهترین مکان برای «کش کردن» منابع ثابت اپلیکیشن (App Shell) است. ما از Cache API برای این کار استفاده می‌کنیم.

Copy Icon JAVASCRIPT - sw.js
const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = ['/', '/styles/main.css', '/script/main.js', '/images/logo.png'];

self.addEventListener('install', event => {
    // Perform install steps
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => {
                console.log('Opened cache');
                return cache.addAll(urlsToCache);
            })
    );
});

در رویداد install، ما یک کش با نام مشخص باز کرده و لیستی از URLهای مهم را در آن ذخیره می‌کنیم. متد event.waitUntil() یک Promise می‌گیرد و به مرورگر می‌گوید که مرحله نصب را تا زمان حل شدن این Promise (یعنی اتمام عملیات کش کردن) موفقیت‌آمیز تلقی نکند.

۳. فعال‌سازی (Activation)

پس از نصب موفق، Service Worker وارد حالت انتظار می‌شود. زمانی که هیچ صفحه‌ای از نسخه قدیمی Service Worker استفاده نکند، نسخه جدید فعال شده و رویداد activate اجرا می‌شود. این رویداد، بهترین مکان برای انجام کارهای پاک‌سازی است، مانند حذف کش‌های قدیمی که دیگر به آنها نیاز نداریم.

رهگیری درخواست‌ها با رویداد fetch

جادوی واقعی Service Worker زمانی اتفاق می‌افتد که فعال شده و کنترل صفحه را به دست می‌گیرد. از این لحظه به بعد، Service Worker برای هر درخواست شبکه‌ای که از صفحه ارسال می‌شود، یک رویداد fetch دریافت می‌کند. این به ما اجازه می‌دهد تا درخواست را رهگیری کرده و تصمیم بگیریم که چگونه به آن پاسخ دهیم.

یک استراتژی رایج، «اول کش، سپس شبکه» (Cache, falling back to network) است. در این الگو، ما ابتدا بررسی می‌کنیم که آیا پاسخی برای این درخواست در کش وجود دارد یا خیر. اگر وجود داشت، پاسخ را از کش برمی‌گردانیم. در غیر این صورت، درخواست را به شبکه ارسال می‌کنیم.

Copy Icon JAVASCRIPT - sw.js
self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request)
            .then(response => {
                // Cache hit - return response from cache
                if (response) {
                    return response;
                }
                // Not in cache - go to the network
                return fetch(event.request);
            })
    );
});

متد event.respondWith() یک Promise می‌گیرد که با یک شیء Response حل می‌شود. در این کد، ما با caches.match() به دنبال یک پاسخ ذخیره شده می‌گردیم. اگر پیدا شد، همان را برمی‌گردانیم. در غیر این صورت، با fetch درخواست اصلی را به شبکه ارسال کرده و نتیجه آن را برمی‌گردانیم. این الگوی ساده، اساس قابلیت کار آفلاین را تشکیل می‌دهد.

در این درس با Service Workers به عنوان یک تکنولوژی تحول‌آفرین در وب آشنا شدیم. دیدیم که چگونه با رهگیری درخواست‌های شبکه و مدیریت کش، می‌توانیم اپلیکیشن‌های وب آفلاین و قابل اعتمادی بسازیم. با این درس، فصل «کار با Workerها» به پایان می‌رسد. ما انواع مختلف ورکرها را برای انجام کارهای پس‌زمینه، اشتراک‌گذاری وضعیت و فعال‌سازی قابلیت‌های PWA بررسی کردیم. در فصل بعدی، «توصیه‌های کاربردی»، به مجموعه‌ای از بهترین شیوه‌ها برای نگهداری، عملکرد و استقرار پروژه‌های جاوااسکریپت خواهیم پرداخت.