`Service Worker` sa JavaScript

`Service Worker` sa JavaScript

Ipinapaliwanag ng artikulong ito ang konsepto ng Service Worker sa JavaScript.

Ipapaliwanag namin ang bawat hakbang mula sa mga batayan ng Service Worker hanggang sa aktuwal na kontrol ng cache.

YouTube Video

offline.html
 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4  <meta charset="UTF-8">
 5  <title>Offline</title>
 6</head>
 7<body>
 8  <h1>You are offline</h1>
 9  <p>This is the offline fallback page.</p>
10</body>
11</html>
style.css
1body {
2  font-family: sans-serif;
3  background-color: #f0f0f0;
4  padding: 20px;
5}
6h1 {
7  color: #333;
8}
javascript-service-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <div class="container">
111        <h2>HTML Sample</h2>
112        <button id="fetchBtn">Fetch Test</button>
113    </div>
114
115    <script>
116        // Override console.log to display messages in the #output element
117        (function () {
118            // Override console.log
119            const originalLog = console.log;
120            console.log = function (...args) {
121                originalLog.apply(console, args);
122                const message = document.createElement('div');
123                message.textContent = args.map(String).join(' ');
124                output.appendChild(message);
125            };
126
127            // Override console.error
128            const originalError = console.error;
129            console.error = function (...args) {
130                originalError.apply(console, args);
131                const message = document.createElement('div');
132                message.textContent = args.map(String).join(' ');
133                message.style.color = 'red'; // Color error messages red
134                output.appendChild(message);
135            };
136        })();
137
138        document.getElementById('executeBtn').addEventListener('click', () => {
139            // Prevent multiple loads
140            if (document.getElementById('externalScript')) return;
141
142            const script = document.createElement('script');
143            script.src = 'javascript-service-worker.js';
144            script.id = 'externalScript';
145            //script.onload = () => console.log('javascript-service-worker.js loaded and executed.');
146            //script.onerror = () => console.log('Failed to load javascript-service-worker.js.');
147            document.body.appendChild(script);
148        });
149    </script>
150</body>
151</html>

Service Worker sa JavaScript

Ang Service Worker ay isang tampok ng JavaScript na namamagitan sa browser at sa network, nagbibigay-daan sa pag-cache ng mga request at suporta sa offline. Ito ay isang pangunahing teknolohiya ng mga PWA (Progressive Web Apps) at nagdadala ng karanasang parang native app sa mga web application.

Ano ang Service Worker?

Ang Service Worker ay isang JavaScript file na tumatakbo sa background thread ng browser. Tumatakbo ito sa hiwalay na thread mula sa pahina, hindi makaka-access sa UI, ngunit maaaring humarang ng mga network request, mag-manage ng caching, at mag-handle ng push notifications.

Ang mga pangunahing tampok ng Service Worker ay kinabibilangan ng mga sumusunod:.

  • Gumagana lamang ito sa HTTPS, maliban kung nasa localhost.
  • Gumagamit ito ng Promise-based asynchronous API.
  • Ito ay event-driven, gumagamit ng mga event tulad ng install, activate, fetch, at push.

Pagrehistro ng Service Worker

Una, sumulat tayo ng code upang irehistro ang Service Worker sa browser.

 1if ('serviceWorker' in navigator) {
 2    window.addEventListener('load', () => {
 3        navigator.serviceWorker.register('/sw.js')
 4        .then(registration => {
 5            console.log(
 6                'Service Worker registered with scope:',
 7                registration.scope
 8            );
 9        })
10        .catch(error => {
11            console.error('Service Worker registration failed:', error);
12        });
13    });
14}

Paliwanag

  • Gamitin ang navigator.serviceWorker.register() para magrehistro ng /sw.js (ang Service Worker file).
  • Maaari mong gamitin ang then para i-handle ang success at catch para sa error handling habang nagrerehistro.
  • Ang registration.scope ay kumakatawan sa saklaw ng path (scope) na apektado ng Service Worker.
  • Sa default, ang scope ay ang directory kung saan matatagpuan ang narehistrong file (sa kasong ito, /sw.js) at mga subdirectory nito.

Saklaw ng Service Worker

Kung nais mong limitahan ang saklaw, maaari mong tukuyin ang scope gamit ang ikalawang argumento ng register.

1navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
2.then(registration => {
3    console.log(
4        'Service Worker registered with scope:',
5        registration.scope
6    );
7});

Paliwanag

  • Sa setting na ito, tanging mga pahina sa ilalim ng /app/ lamang ang mako-kontrol ng Service Worker.

Paglikha ng Service Worker file

Susunod, gumawa ng file na tinatawag na sw.js at ipatupad ang mga pangunahing event.

1// sw.js
2const CACHE_NAME = 'my-cache-v1';
3const urlsToCache = [
4    '/',
5    '/index.html',
6    '/styles.css',
7    '/script.js',
8    '/offline.html'
9];

Tinutukoy ng code na ito ang listahan ng mga resources na ise-save sa cache.

Mga tungkulin at mekanismo ng bawat event

install

 1// Install event (initial caching)
 2self.addEventListener('install', event => {
 3    console.log('[ServiceWorker] Install');
 4    event.waitUntil(
 5        caches.open(CACHE_NAME).then(cache => {
 6            console.log('[ServiceWorker] Caching app shell');
 7            return cache.addAll(urlsToCache);
 8        })
 9    );
10});
  • Ang self.addEventListener('install') ay na-a-activate kapag ang Service Worker ay nairehistro sa unang pagkakataon. Sa stage na ito, ang mga kinakailangang file ay pre-cached na.

activate

 1// Activation event (delete old caches)
 2self.addEventListener('activate', event => {
 3    console.log('[ServiceWorker] Activate');
 4    event.waitUntil(
 5        caches.keys().then(keyList => {
 6            return Promise.all(keyList.map(key => {
 7                if (key !== CACHE_NAME) {
 8                    console.log('[ServiceWorker] Removing old cache:', key);
 9                    return caches.delete(key);
10                }
11            }));
12        })
13    );
14    return self.clients.claim();
15});
  • Sa activate event, ang mga lumang cache ay binubura para ma-optimize ang storage. Tanging ang cache ng bagong bersyon lamang ang itinatabi.

fetch

1// Fetch event (cache-first strategy)
2self.addEventListener('fetch', event => {
3  console.log('[ServiceWorker] Fetch', event.request.url);
4    event.respondWith(
5        caches.match(event.request).then(response => {
6            return response || fetch(event.request).catch(() => caches.match('/offline.html'));
7        })
8    );
9});

Lahat ng HTTP request ay hinaharang—kung may naka-cache na bersyon, iyon ang ibinabalik; kung wala, kinukuha mula sa network. Kapag offline, isang alternatibong pahina (hal. offline.html) ang ibinabalik.

Kinukumpirma ang operasyon

Tingnan natin kung paano talaga gumagana ang Service Worker.

 1document.getElementById('fetchBtn').addEventListener('click', () => {
 2    fetch('/style.css')
 3        .then(response => response.text())
 4        .then(data => {
 5            console.log('Fetched data:', data);
 6        })
 7        .catch(error => {
 8            console.error('Fetch failed:', error);
 9        });
10});
  • Dito, sinusuri natin ang pagpaparehistro ng Service Worker at ang kilos ng pagkuha ng mga resource sa pamamagitan ng pag-click sa test button.

Mga Halimbawa ng Caching Strategies

Ang mga sumusunod ay karaniwang caching strategies:.

Cache First

Narito ang halimbawa ng implementasyon para sa Cache First strategy:.

1self.addEventListener('fetch', event => {
2    event.respondWith(
3        caches.match(event.request).then(response => {
4            return response || fetch(event.request);
5        })
6    );
7});
  • Ang code na ito ay gumagamit ng cache-first strategy, kung saan ang hinihiling na resource ay ibinibigay mula sa cache kung ito ay available; kung hindi, ito ay kinukuha mula sa network.

Network First

Narito ang halimbawa ng implementasyon para sa Network First strategy:.

 1self.addEventListener('fetch', event => {
 2    event.respondWith(
 3        fetch(event.request)
 4            .then(response => {
 5                return caches.open(CACHE_NAME).then(cache => {
 6                    cache.put(event.request, response.clone());
 7                    return response;
 8                });
 9            })
10            .catch(() => caches.match(event.request))
11    );
12});
  • Ang code na ito ay gumagamit ng network-first strategy, kung saan ang hinihiling na resource ay unang kinukuha mula sa network, at kung ito ay mabigo, ito ay kinukuha mula sa cache.

I-cache lamang ang mga style at JavaScript, at i-access ang APIs real-time

Narito ang halimbawa ng implementasyon kung saan naka-cache ang styles at JavaScript habang real-time na ina-access ang API:.

 1self.addEventListener('fetch', event => {
 2    if (event.request.url.includes('/api/')) {
 3        // Fetch API responses in real-time without caching
 4        return;
 5    }
 6
 7    // Use cache-first strategy for static files
 8    event.respondWith(
 9        caches.match(event.request).then(response => {
10            return response || fetch(event.request);
11        })
12    );
13});
  • Ang code na ito ay laging gumagawa ng API requests nang real-time at gumagamit ng cache-first strategy para sa mga static files tulad ng stylesheets at JavaScript.

Daloy ng pag-update

Ang daloy ng pag-update ng isang Service Worker ay ang mga sumusunod:.

  1. Natuklasan ang bagong sw.js.
  2. Na-trigger ang install event.
  3. Maghihintay hanggang maging idle ang naunang Service Worker.
  4. Na-trigger ang activate event.
  5. Lumilipat na sa bagong Service Worker.
  6. Ang event na controllerchange ay nai-trigger.

Pag-detect ng update

Kapag ang Service Worker ay na-install na, patuloy na ginagamit ang luma hanggang sa susunod na pagbisita. Upang mag-apply ng mga update, karaniwan nang gumamit ng code na nagde-detect ng mga update at nirere-load ang pahina.

1navigator.serviceWorker.addEventListener('controllerchange', () => {
2    window.location.reload();
3});
  • Ang event na controllerchange ay nai-trigger kapag ang controller ng Service Worker, ibig sabihin ang Service Worker na kumokontrol sa kasalukuyang pahina, ay nagbago.
  • Ang mga pahina na kasalukuyang bukas ay patuloy na gumagamit ng kasalukuyang Service Worker, at ang bagong install na Service Worker ay hindi agad epektibo sa mga pahinang iyon. Dahil dito, ginagamit ang isang paraan kung saan ang controllerchange event ay ginagamit upang matukoy na may bagong controller na naging aktibo, saka nire-reload ang pahina upang agad na ma-apply ang update.

Mga Paalala at Pinakamahusay na Gawain

Kapag gumagamit ng Service Worker, tandaan ang mga sumusunod:.

  • Kailangan ng HTTPS Dahil sa mga security restriction, hindi ito gumagana sa http:// maliban sa localhost.

  • May Hash na Mga Pangalan ng File Maaaring isama sa pangalan ng cache ang file name, URL, at impormasyong may kaugnayan sa bersyon.

  • Komunikasyon sa Mga Kliyente Gamitin ang postMessage para magkomunika sa pagitan ng Service Worker at ng JavaScript ng pahina.

Buod

Ang Service Worker ay mahalagang teknolohiya para sa suporta sa offline at pagpapabuti ng performance ng mga web app. Sa pamamagitan ng pag-unawa sa pangunahing daloy ng pag-install, activation, at fetch handling, at paggamit ng tamang caching strategies, makakabuo ka ng mas mataas na kalidad ng web application.

Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.

YouTube Video