कुछ मामलों में, वेब ऐप्लिकेशन को पेज और सर्विस वर्कर के बीच दो-तरफ़ा कम्यूनिकेशन चैनल बनाने की ज़रूरत पड़ सकती है.
उदाहरण के लिए: किसी पॉडकास्ट के PWA में ऐसी सुविधा बनाई जा सकती है जिससे उपयोगकर्ता ऑफ़लाइन इस्तेमाल के लिए एपिसोड डाउनलोड कर सके. साथ ही, सर्विस वर्कर को पेज की प्रोग्रेस के बारे में नियमित रूप से जानकारी रखने की सुविधा मिल सके. इससे मुख्य थ्रेड यूज़र इंटरफ़ेस (यूआई) को अपडेट कर सकता है.
इस गाइड में, हम अलग-अलग एपीआई, Workbox लाइब्रेरी, और कुछ बेहतर केस के साथ-साथ, विंडो और सर्विस वर्कर के बीच दोतरफ़ा कम्यूनिकेशन को लागू करने के अलग-अलग तरीकों के बारे में बताएंगे.
Workbox का इस्तेमाल करना
workbox-window
, वर्कबॉक्स लाइब्रेरी के मॉड्यूल का एक सेट है. इसे विंडो में चलने के लिए बनाया गया है. Workbox
क्लास में messageSW()
तरीका मिलता है. इसकी मदद से, इंस्टेंस के रजिस्टर किए गए सर्विस वर्कर को मैसेज भेजा जा सकता है और रिस्पॉन्स मिलने का इंतज़ार किया जा सकता है.
यह पेज कोड एक नया Workbox
इंस्टेंस बनाता है और सर्विस वर्कर को इसका वर्शन पाने के लिए मैसेज भेजता है:
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
सर्विस वर्कर, मैसेज लिसनर को लागू करता है और रजिस्टर किए गए सर्विस वर्कर को जवाब देता है:
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
इसके तहत, लाइब्रेरी ऐसे ब्राउज़र एपीआई का इस्तेमाल करती है जिसकी समीक्षा हम अगले सेक्शन में करेंगे: Message Channel. हालांकि, इसमें कई तरीकों से जानकारी शामिल की गई है, जिससे इसे इस्तेमाल करना आसान हो जाता है. साथ ही, सभी ब्राउज़र पर काम करने वाले एपीआई का फ़ायदा लिया जाता है.
ब्राउज़र एपीआई इस्तेमाल करना
अगर Workbox लाइब्रेरी आपकी ज़रूरतों के हिसाब से काफ़ी नहीं है, तो पेजों और सर्विस वर्कर के बीच "टू-वे" कम्यूनिकेशन लागू करने के लिए, निचले लेवल के कई एपीआई उपलब्ध हैं. उनमें कुछ समानताएं और अंतर हैं:
समानताएं:
- सभी मामलों में कम्यूनिकेशन,
postMessage()
इंटरफ़ेस से शुरू होता है और दूसरे परmessage
हैंडलर को लागू करने पर मिलता है. - सभी उपलब्ध एपीआई की मदद से, हम इस्तेमाल के एक जैसे उदाहरण लागू कर सकते हैं. हालांकि, कुछ एपीआई कुछ स्थितियों में, ऐप्लिकेशन के डेवलपमेंट को आसान बना सकते हैं.
अंतर:
- बातचीत के दूसरे पक्ष की पहचान करने के लिए, इनमें अलग-अलग तरीके अपनाए जाते हैं. इनमें से कुछ दस्तावेज़, दूसरे संदर्भ का साफ़ तौर पर रेफ़रंस देते हैं. वहीं, कुछ कंपनियां, दोनों तरफ़ मौजूद प्रॉक्सी ऑब्जेक्ट के ज़रिए, बिना किसी जानकारी के बातचीत कर सकती हैं.
- हर ब्राउज़र के लिए सहायता अलग-अलग होती है.
ब्रॉडकास्ट चैनल एपीआई
Broadcast Channel API, BroadcastChannel ऑब्जेक्ट की मदद से, ब्राउज़िंग कॉन्टेक्स्ट के बीच बुनियादी कम्यूनिकेशन करने की अनुमति देता है.
इसे लागू करने के लिए, सबसे पहले हर कॉन्टेक्स्ट को एक ही आईडी वाले BroadcastChannel
ऑब्जेक्ट को इंस्टैंशिएट करना होगा और इससे मैसेज भेजना और पाना होगा:
const broadcast = new BroadcastChannel('channel-123');
किसी भी तरह के कॉन्टेक्स्ट पर मैसेज भेजने के लिए, BroadcastChannel ऑब्जेक्ट postMessage()
इंटरफ़ेस दिखाता है:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
ब्राउज़र का कोई भी कॉन्टेक्स्ट, BroadcastChannel
ऑब्जेक्ट के onmessage
तरीके से मैसेज सुन सकता है:
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
जैसा कि देखा जा चुका है, किसी खास संदर्भ का कोई साफ़ संदर्भ नहीं है, इसलिए पहले सर्विस वर्कर या किसी खास क्लाइंट का रेफ़रंस लेने की ज़रूरत नहीं है.
नुकसान यह है कि इस समय, एपीआई को Chrome, Firefox, और Edge पर काम करता है. हालांकि, Safari जैसे दूसरे ब्राउज़र अभी भी इस पर काम नहीं करते.
क्लाइंट एपीआई
Client API, आपको उन सभी WindowClient
ऑब्जेक्ट की पहचान करने की अनुमति देता है जो उन ऐक्टिव टैब को दिखाते हैं जिन्हें सर्विस वर्कर कंट्रोल कर रहा है.
इस पेज को एक ही सर्विस वर्कर कंट्रोल करता है. इसलिए, यह सीधे serviceWorker
इंटरफ़ेस की मदद से, ऐक्टिव सर्विस वर्कर को मैसेज सुनता है और उन्हें भेजता है:
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
इसी तरह, सर्विस वर्कर onmessage
लिसनर लागू करके मैसेज सुनता है:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
अपने किसी भी क्लाइंट से संपर्क करने के लिए, सर्विस वर्कर Clients.matchAll()
और Clients.get()
जैसे तरीकों को लागू करके, WindowClient
ऑब्जेक्ट की एक कलेक्शन हासिल करता है. इसके बाद,
इनमें से किसी एक को postMessage()
किया जा सकता है:
//Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
if (clients && clients.length) {
//Respond to last focused tab
clients[0].postMessage({type: 'MSG_ID'});
}
});
Client API
, सर्विस वर्कर के सभी चालू टैब से आसानी से कम्यूनिकेट करने का एक अच्छा विकल्प है. यह एपीआई सभी बड़े ब्राउज़र पर काम करता है. हालांकि, ऐसा हो सकता है कि इसके सभी तरीके उपलब्ध न हों. इसलिए, इसे अपनी साइट में लागू करने से पहले, यह देख लें कि यह ब्राउज़र पर काम करती हो.
मैसेज चैनल
मैसेज चैनल में, पोर्ट तय करने और उसे एक संदर्भ से दूसरे संदर्भ में पास करने की ज़रूरत होती है. इससे टू-वे कम्यूनिकेशन चैनल बनाया जा सकता है.
चैनल शुरू करने के लिए, पेज MessageChannel
ऑब्जेक्ट को इंस्टैंशिएट करता है और इसका इस्तेमाल, रजिस्टर किए गए सर्विस वर्कर को पोर्ट भेजने के लिए करता है. इस पेज से दूसरे कॉन्टेक्स्ट से मैसेज पाने के लिए, onmessage
लिसनर भी लागू होता है:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
सर्विस वर्कर को पोर्ट मिलता है, वह इसके रेफ़रंस को सेव करता है, और दूसरी साइड पर मैसेज भेजने के लिए उसका इस्तेमाल करता है:
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
फ़िलहाल, MessageChannel
का इस्तेमाल सभी बड़े ब्राउज़र पर किया जा सकता है.
बेहतर एपीआई: बैकग्राउंड सिंक और बैकग्राउंड फ़ेच
इस गाइड में, हमने कम्यूनिकेशन की टू-वे तकनीकों को लागू करने के तरीकों के बारे में जाना. ये तरीके, आसान मामलों में इस्तेमाल किए जाते हैं. जैसे, कार्रवाई के बारे में जानकारी देने वाला स्ट्रिंग मैसेज भेजना या एक कॉन्टेक्स्ट से दूसरे कॉन्टेक्स्ट में कैश मेमोरी में सेव करने के लिए यूआरएल की सूची. इस सेक्शन में हम उन दो एपीआई के बारे में जानेंगे जिनसे खास स्थितियों को मैनेज किया जा सकता है: कनेक्टिविटी की कमी और लंबे डाउनलोड.
बैकग्राउंड सिंक
कोई चैट ऐप्लिकेशन यह पक्का करना चाहता है कि खराब कनेक्टिविटी की वजह से मैसेज कभी न खोएं. बैकग्राउंड सिंक एपीआई आपको उन कार्रवाइयों को टालने की सुविधा देता है जिन्हें फिर से कोशिश करने की ज़रूरत नहीं होती. ऐसा तब होता है, जब उपयोगकर्ता के पास अच्छी कनेक्टिविटी हो. इससे यह पक्का करने में मदद मिलती है कि उपयोगकर्ता जो भी भेजना चाहता है, उसे असल में भेजा जाए.
postMessage()
इंटरफ़ेस के बजाय, पेज sync
को रजिस्टर करता है:
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
इसके बाद, सर्विस वर्कर मैसेज को प्रोसेस करने के लिए sync
इवेंट सुनता है:
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
फ़ंक्शन doSomeStuff()
को फ़ंक्शन की सफलता/असफलता का संकेत देना चाहिए. अगर यह पूरा होता है, तो सिंक पूरा हो जाता है. अगर ऐसा नहीं होता, तो फिर से सिंक करने के लिए, सिंक करने की प्रोसेस को शेड्यूल
किया जाएगा. फिर से सिंक करने की सुविधा, कनेक्टिविटी की भी इंतज़ार करती है और एक्सपोनेन्शियल बैक-ऑफ़ लागू करती है.
एक बार कार्रवाई हो जाने के बाद, सर्विस वर्कर पहले एक्सप्लोर किए गए किसी भी कम्यूनिकेशन एपीआई का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) अपडेट करने के लिए पेज पर फिर से संपर्क कर सकता है.
Google Search, खराब कनेक्टिविटी की वजह से पूरी न हो पाने वाली क्वेरी को बनाए रखने के लिए, बैकग्राउंड सिंक का इस्तेमाल करता है. साथ ही, बाद में उपयोगकर्ता के ऑनलाइन होने पर, दोबारा इन क्वेरी का इस्तेमाल करने की कोशिश करता है. कार्रवाई पूरी होने के बाद, वे वेब पुश नोटिफ़िकेशन के ज़रिए उपयोगकर्ता को नतीजे के बारे में बताते हैं:
बैकग्राउंड फ़ेच
मैसेज भेजने जैसे छोटे काम या कैश मेमोरी में सेव किए जाने वाले यूआरएल की सूची के लिए, अब तक एक्सप्लोर किए गए विकल्प अच्छे विकल्प हैं. अगर टास्क में ज़्यादा समय लगता है, तो ब्राउज़र के ज़रिए सर्विस वर्कर की मौत हो जाएगी. ऐसा न होने पर, उपयोगकर्ता की निजता और बैटरी को नुकसान पहुंच सकता है.
बैकग्राउंड फ़ेच एपीआई आपको सर्विस वर्कर को लंबे टास्क ऑफ़लोड करने देता है. जैसे, फ़िल्में, पॉडकास्ट या किसी गेम के लेवल डाउनलोड करना.
पेज के ज़रिए सर्विस वर्कर से संपर्क करने के लिए, postMessage()
के बजाय backgroundFetch.fetch
का इस्तेमाल करें:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch(
'my-fetch',
['/ep-5.mp3', 'ep-5-artwork.jpg'],
{
title: 'Episode 5: Interesting things.',
icons: [
{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
},
],
downloadTotal: 60 * 1024 * 1024,
},
);
});
BackgroundFetchRegistration
ऑब्जेक्ट की मदद से, पेज progress
इवेंट सुनता है, ताकि यह पता चल सके कि डाउनलोड कहां तक हुआ है:
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(
(bgFetch.downloaded / bgFetch.downloadTotal) * 100,
);
console.log(`Download progress: ${percent}%`);
});
अगले चरण
इस गाइड में, हमने पेज और सर्विस वर्कर के बीच होने वाले कम्यूनिकेशन के सबसे सामान्य मामले (दोनों-तरफ़ा कम्यूनिकेशन) के बारे में जाना.
कई बार, एक व्यक्ति को जवाब पाए बिना, दूसरे से बातचीत करने के लिए सिर्फ़ एक कॉन्टेक्स्ट की ज़रूरत होती है. अपने पेजों पर और सर्विस वर्कर के लिए, एकतरफ़ा तकनीकें लागू करने के तरीके जानने के लिए, यहां दी गई गाइड देखें. इन तकनीकों के साथ-साथ इस्तेमाल के उदाहरण और प्रोडक्शन के उदाहरण भी दिए गए हैं:
- इंपेरेटिव कैश मेमोरी गाइड: किसी सर्विस वर्कर को पेज से रिसॉर्स को पहले से कैश मेमोरी में सेव करने के लिए कॉल करना (उदाहरण के लिए, प्रीफ़ेच करने की स्थितियों में).
- ब्रॉडकास्ट अपडेट: ज़रूरी अपडेट के बारे में जानकारी देने के लिए, सर्विस वर्कर से पेज को कॉल करना (जैसे, वेबऐप का नया वर्शन उपलब्ध है).