`Service Worker` জাভাস্ক্রিপ্ট-এ
এই নিবন্ধটি জাভাস্ক্রিপ্ট-এর Service Worker
ধারণা ব্যাখ্যা করে।
আমরা ধাপে ধাপে Service Worker
-এর মৌলিক বিষয় থেকে শুরু করে ব্যবহারিক ক্যাশ নিয়ন্ত্রণ পর্যন্ত ব্যাখ্যা করব।
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 & 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
জাভাস্ক্রিপ্ট-এ
Service Worker
হলো জাভাস্ক্রিপ্ট-এর একটি ফিচার যা ব্রাউজার এবং নেটওয়ার্কের মাঝে অবস্থান নেয়, অনুরোধ ক্যাশিং এবং অফলাইন সাপোর্ট সক্ষম করে। এটি PWA (Progressive Web App)-এর অন্যতম প্রধান প্রযুক্তি এবং ওয়েব অ্যাপ্লিকেশনকে নেটিভ অ্যাপের মতো অভিজ্ঞতা প্রদান করে।
Service Worker
কী?
Service Worker
হচ্ছে একটি জাভাস্ক্রিপ্ট ফাইল যা ব্রাউজারের ব্যাকগ্রাউন্ড থ্রেডে চলে। এটি পেজ থেকে আলাদা থ্রেডে চলে, UI-তে প্রবেশ করতে পারে না, তবে নেটওয়ার্ক অনুরোধ আটকাতে, ক্যাশ ব্যবস্থাপনা ও পুশ নোটিফিকেশন পরিচালনা করতে পারে।
Service Worker
-এর মূল বৈশিষ্ট্যগুলো হলো:।
- এটি শুধু HTTPS-এ কাজ করে, localhost ছাড়া।
- এটি Promise-ভিত্তিক অ্যাসিনক্রোনাস API ব্যবহার করে।
- এটি ইভেন্ট-চালিত, যেমন
install
,activate
,fetch
, এবংpush
ইভেন্ট ব্যবহার করে।
Service Worker
রেজিস্ট্রেশন করা
প্রথমে, ব্রাউজারে Service Worker
রেজিস্ট্রেশনের কোড লিখতে হবে।
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}
ব্যাখ্যা
navigator.serviceWorker.register()
ব্যবহার করে/sw.js
(অর্থাৎService Worker
ফাইল) রেজিস্টার করুন।- রেজিস্ট্রেশনের সময় সফলতা পরিচালনার জন্য
then
এবং ত্রুটি পরিচালনার জন্যcatch
ব্যবহার করা যায়। registration.scope
দ্বারা বোঝানো হয় কোন পাথ সীমা (scope
) এর উপরService Worker
প্রভাব ফেলে।- ডিফল্টভাবে, স্কোপটি সেই ডিরেক্টরি যেখানে রেজিস্টারকৃত ফাইল (এই ক্ষেত্রে,
/sw.js
) রয়েছে এবং তার সাবডিরেক্টরিগুলি।
Service Worker
-এর স্কোপ
আপনি যদি স্কোপ সীমাবদ্ধ করতে চান, তাহলে register
-এর দ্বিতীয় আর্গুমেন্ট ব্যবহার করে scope
নির্দিষ্ট করতে পারেন।
1navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
2.then(registration => {
3 console.log(
4 'Service Worker registered with scope:',
5 registration.scope
6 );
7});
ব্যাখ্যা
- এই সেটিংয়ের মাধ্যমে শুধুমাত্র
/app/
-এর অধীনে থাকা পেজগুলোService Worker
দ্বারা নিয়ন্ত্রিত হবে।
Service Worker
ফাইল তৈরি করা
এরপর, sw.js
নামে একটি ফাইল তৈরি করুন এবং মৌলিক ইভেন্টগুলো সংযোজন করুন।
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];
এই কোডটি ক্যাশে রাখার জন্য রিসোর্সের একটি তালিকা নির্ধারণ করে।
প্রতিটি ইভেন্টের ভূমিকা ও কার্যপ্রণালী
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});
self.addEventListener('install')
তখনই চালু হয় যখনService Worker
প্রথমবার রেজিস্টার হয়। এই স্তরে, প্রয়োজনীয় ফাইলগুলো প্রি-ক্যাশ করা হয়।
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});
activate
ইভেন্টে, পুরনো ক্যাশগুলো মুছে ফেলে স্টোরেজ অপটিমাইজ করা হয়। শুধুমাত্র নতুন ভার্সনের ক্যাশ রাখা হয়।
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});
সব HTTP অনুরোধ আটকানো হয়—যদি ক্যাশ করা সংস্করণ বিদ্যমান থাকে, তবে তা ফেরত দেওয়া হয়; না থাকলে নেটওয়ার্ক থেকে আনা হয়। অফলাইনে থাকলে বিকল্প কোনো পেজ (যেমন offline.html
) ফিরিয়ে দেওয়া হয়।
অপারেশন নিশ্চিত করা হচ্ছে
আসুন আমরা আসলে দেখি কিভাবে 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});
- এখানে, আমরা
Service Worker
-এর রেজিস্ট্রেশন এবং টেস্ট বোতাম ক্লিক করে রিসোর্স ফেচ করার কার্যকলাপ যাচাই করি।
ক্যাশিং কৌশলের উদাহরণ
নিম্নলিখিত হলো কিছু প্রচলিত ক্যাশিং কৌশল:।
ক্যাশ ফার্স্ট
ক্যাশ ফার্স্ট কৌশলের জন্য একটি উদাহরণ ইমপ্লিমেন্টেশনঃ।
1self.addEventListener('fetch', event => {
2 event.respondWith(
3 caches.match(event.request).then(response => {
4 return response || fetch(event.request);
5 })
6 );
7});
- এই কোডটি একটি ক্যাশ-প্রথম কৌশল প্রয়োগ করে, যেখানে অনুরোধিত রিসোর্সটি ক্যাশে থাকলে তা ফেরত দেওয়া হয়; যদি না থাকে, তখন এটি নেটওয়ার্ক থেকে আনা হয়।
নেটওয়ার্ক ফার্স্ট
নেটওয়ার্ক ফার্স্ট কৌশলের জন্য একটি উদাহরণ ইমপ্লিমেন্টেশনঃ।
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});
- এই কোডটি একটি নেটওয়ার্ক-প্রথম কৌশল প্রয়োগ করে, যেখানে অনুরোধিত রিসোর্সটি প্রথমে নেটওয়ার্ক থেকে আনা হয়, এবং যদি তা ব্যর্থ হয়, তাহলে এটি ক্যাশ থেকে পুনরুদ্ধার করা হয়।
শুধুমাত্র স্টাইল ও জাভাস্ক্রিপ্ট ক্যাশ করুন, API-তে রিয়াল-টাইমে অ্যাক্সেস করুন
এখানে একটি উদাহরণ ইমপ্লিমেন্টেশন দেওয়া হলো যেখানে স্টাইল ও জাভাস্ক্রিপ্ট ক্যাশ হয়, আর 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});
- এই কোডটি সবসময় এপিআই অনুরোধসমূহ তাৎক্ষণিকভাবে অ্যাক্সেস করে এবং স্ট্যাটিক ফাইল যেমন স্টাইলশিট ও জাভাস্ক্রিপ্টের জন্য ক্যাশ-প্রথম কৌশল প্রয়োগ করে।
আপডেট প্রবাহ
একটি সার্ভিস ওয়ার্কারের আপডেট প্রবাহ নিম্নরূপঃ।
১. নতুন sw.js
শনাক্ত হয়।
২. install
ইভেন্ট চালু হয়।
৩. পূর্ববর্তী Service Worker
আইডল না হওয়া পর্যন্ত অপেক্ষা করা হয়।
৪. activate
ইভেন্ট চালু হয়।
৫. নতুন Service Worker-এ পরিবর্তন হয়।
৬. controllerchange
ইভেন্ট চালু হয়।
আপডেট সনাক্তকরণ
একবার Service Worker
ইন্সটল হলে, পুরনোটি পরবর্তী ভিজিট পর্যন্ত ব্যবহার করা হয়। আপডেট কার্যকর করতে, সাধারণত এমন কোড ব্যবহার করা হয় যা আপডেট সনাক্ত করে এবং পৃষ্ঠা রিলোড করে।
1navigator.serviceWorker.addEventListener('controllerchange', () => {
2 window.location.reload();
3});
controllerchange
ইভেন্টটি চালু হয় যখন সার্ভিস ওয়ার্কারের কন্ট্রোলার, অর্থাৎ বর্তমান পৃষ্ঠাটি নিয়ন্ত্রণকারী সার্ভিস ওয়ার্কারটি, পরিবর্তিত হয়।- যেসব পৃষ্ঠা ইতিমধ্যে খোলা আছে, সেগুলি বর্তমান সার্ভিস ওয়ার্কার ব্যবহার চালিয়ে যায়; নতুনভাবে ইনস্টল হওয়া সার্ভিস ওয়ার্কার সঙ্গে সঙ্গে ঐ পৃষ্ঠাগুলিতে কার্যকর হয় না। তাই, এমন একটি পদ্ধতি ব্যবহৃত হয় যেখানে
controllerchange
ইভেন্টটি ব্যবহার করে বোঝা যায় যে নতুন কন্ট্রোলার সক্রিয় হয়েছে; এরপর সাথে সাথে আপডেট কার্যকর করতে পৃষ্ঠাটি রিলোড করা হয়।
সতর্কতা ও সর্বোত্তম চর্চাসমূহ
Service Worker
ব্যবহারের সময় নিম্নোক্ত বিষয়গুলো মনে রাখতে হবে:।
-
HTTPS প্রয়োজনীয় নিরাপত্তাজনিত কারণে, এটি
localhost
ছাড়াhttp://
-এ কাজ করে না। -
হ্যাশড ফাইল নাম ব্যবহার করুন ক্যাশ নামের মধ্যে ফাইল নাম, URL ও ভার্সন তথ্য থাকতে পারে।
-
ক্লায়েন্টের সাথে যোগাযোগ পৃষ্ঠার জাভাস্ক্রিপ্ট এবং
Service Worker
-এর মধ্যে যোগাযোগ করতেpostMessage
ব্যবহার করুন।
সারসংক্ষেপ
Service Worker
ওয়েব অ্যাপগুলোর জন্য অফলাইন সমর্থন এবং পারফরমেন্স উন্নয়নের অপরিহার্য প্রযুক্তি। ইনস্টলেশন, অ্যাক্টিভেশন এবং ফেচ পরিচালনার মৌলিক প্রবাহ এবং উপযুক্ত ক্যাশিং কৌশল প্রয়োগের মাধ্যমে, আপনি আরও উন্নত মানের ওয়েব অ্যাপ তৈরি করতে পারবেন।
আপনি আমাদের ইউটিউব চ্যানেলে ভিজ্যুয়াল স্টুডিও কোড ব্যবহার করে উপরের নিবন্ধটি অনুসরণ করতে পারেন। দয়া করে ইউটিউব চ্যানেলটিও দেখুন।