सर्विस वर्कर के साथ दोतरफ़ा बातचीत

Andrew Guan
Andrew Guan

कुछ मामलों में, हो सकता है कि वेब ऐप्लिकेशन को पेज और सेवा वर्कर के बीच दोतरफ़ा कम्यूनिकेशन चैनल सेट अप करना पड़े.

उदाहरण के लिए: पॉडकास्ट के पीडब्ल्यूए में एक ऐसी सुविधा बनाई जा सकती है जिससे उपयोगकर्ता ऑफ़लाइन देखने के लिए एपिसोड डाउनलोड कर सके. साथ ही, सर्विस वर्कर को पेज पर नियमित रूप से प्रोग्रेस के बारे में जानकारी देने की अनुमति मिल सके, ताकि मुख्य थ्रेड यूज़र इंटरफ़ेस (यूआई) को अपडेट कर सके.

इस गाइड में, हम विंडो और सेवा वर्कअर कॉन्टेक्स्ट के बीच दोतरफ़ा कम्यूनिकेशन लागू करने के अलग-अलग तरीकों के बारे में बताएंगे. इसके लिए, हम अलग-अलग एपीआई, Workbox लाइब्रेरी, और कुछ बेहतर उदाहरणों का इस्तेमाल करेंगे.

डायग्राम में एक सर्विस वर्कर और एक पेज को दिखाया गया है, जिससे मैसेज की अदला-बदली होती है.

Workbox का इस्तेमाल करना

workbox-window, Workbox लाइब्रेरी के उन मॉड्यूल का सेट है जिन्हें विंडो के संदर्भ में चलाया जाता है. 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);
  }
});

लाइब्रेरी में एक ऐसे ब्राउज़र एपीआई का इस्तेमाल होता है जिसकी समीक्षा हम अगले सेक्शन में करेंगे: मैसेज चैनल. हालांकि, इसमें इसे लागू करने की जानकारी को ऐब्स्ट्रैक्ट किया गया है, जिससे इस एपीआई के अलग-अलग ब्राउज़र के लिए उपलब्ध सहायता का फ़ायदा लेते हुए, इसे इस्तेमाल करना आसान हो गया है.

Workbox विंडो का इस्तेमाल करके, पेज और सेवा वर्कर के बीच दोतरफ़ा कम्यूनिकेशन को दिखाने वाला डायग्राम.

ब्राउज़र एपीआई का इस्तेमाल करना

अगर Workbox लाइब्रेरी आपकी ज़रूरतों के हिसाब से काफ़ी नहीं है, तो पेजों और सर्विस वर्कर के बीच "टू-वे" कम्यूनिकेशन लागू करने के लिए, कई निचले-लेवल के एपीआई उपलब्ध हैं. दोनों में कुछ समानताएं और अंतर हैं:

समानताएं:

  • सभी मामलों में, postMessage() इंटरफ़ेस के ज़रिए एक तरफ़ से बातचीत शुरू होती है और message हैंडलर लागू करके, दूसरी तरफ़ से उसे रिसीव किया जाता है.
  • असल में, सभी उपलब्ध एपीआई की मदद से, एक जैसे इस्तेमाल के उदाहरण लागू किए जा सकते हैं. हालांकि, कुछ मामलों में इनमें से कुछ एपीआई का इस्तेमाल करने से, डेवलपमेंट आसान हो सकता है.

अंतर:

  • बातचीत के दूसरे पक्ष की पहचान करने के लिए, उनके पास अलग-अलग तरीके होते हैं: कुछ में दूसरे कॉन्टेक्स्ट के लिए साफ़ तौर पर रेफ़रंस का इस्तेमाल किया जाता है, जबकि अन्य दोनों पक्षों पर इंस्टैंशिएट किए गए प्रॉक्सी ऑब्जेक्ट के ज़रिए, साफ़ तौर पर बातचीत कर सकते हैं.
  • ब्राउज़र समर्थन उनके बीच भिन्न होता है.
पेज और सेवा वर्कर के बीच दोतरफ़ा कम्यूनिकेशन और उपलब्ध ब्राउज़र एपीआई को दिखाने वाला डायग्राम.

ब्रॉडकास्ट चैनल एपीआई

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 54.
  • Edge: 79.
  • Firefox: 38.
  • Safari: 15.4.

सोर्स

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 जैसे दूसरे ब्राउज़र पर अभी यह सुविधा काम नहीं करती.

क्लाइंट एपीआई

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 40.
  • एज: 17.
  • Firefox: 44.
  • Safari: 11.1.

सोर्स

क्लाइंट एपीआई की मदद से, उन सभी 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 एक अच्छा विकल्प है. यह एपीआई सभी मुख्य ब्राउज़र पर काम करता है. हालांकि, हो सकता है कि इसके सभी तरीके उपलब्ध न हों. इसलिए, अपनी साइट पर इसे लागू करने से पहले, ब्राउज़र पर काम करने की सुविधा देख लें.

मैसेज चैनल

ब्राउज़र सहायता

  • Chrome: 2.
  • Edge: 12.
  • Firefox: 41.
  • Safari: 5.

सोर्स

मैसेज चैनल को टू-वे कम्यूनिकेशन चैनल बनाने के लिए, एक कॉन्टेक्स्ट से दूसरे कॉन्टेक्स्ट में पोर्ट तय करना और उसे पास करना ज़रूरी है.

चैनल को शुरू करने के लिए, पेज एक MessageChannel ऑब्जेक्ट को इंस्टैंशिएट करता है और रजिस्टर किए गए सेवा वर्कर को पोर्ट भेजने के लिए उसका इस्तेमाल करता है. पेज पर, दूसरे कॉन्टेक्स्ट से मैसेज पाने के लिए, onmessage listener भी लागू किया जाता है:

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 की सुविधा सभी मुख्य ब्राउज़र पर काम करती है.

बेहतर एपीआई: बैकग्राउंड सिंक और बैकग्राउंड फ़ेच

इस गाइड में, हमने दो-तरफ़ा कम्यूनिकेशन तकनीकों को लागू करने के तरीकों के बारे में बताया है. ये तकनीकें, आसान मामलों में काम आती हैं. जैसे, किसी कार्रवाई के बारे में बताने वाला स्ट्रिंग मैसेज भेजना या एक कॉन्टेक्स्ट से दूसरे कॉन्टेक्स्ट में कैश मेमोरी में सेव करने के लिए यूआरएल की सूची भेजना. इस सेक्शन में, हम दो एपीआई के बारे में जानेंगे. इनकी मदद से, कुछ खास स्थितियों को मैनेज किया जा सकता है: कनेक्टिविटी की समस्या और लंबे समय तक डाउनलोड होने वाले वीडियो.

बैकग्राउंड सिंक

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 49.
  • Edge: 79.
  • Firefox: समर्थित नहीं.
  • Safari: यह सुविधा काम नहीं करती.

सोर्स

चैट ऐप्लिकेशन यह पक्का करना चाहता है कि खराब कनेक्टिविटी की वजह से मैसेज कभी न मिटें. Background Sync API की मदद से, उपयोगकर्ता के पास बेहतर कनेक्टिविटी होने पर, कार्रवाइयों को फिर से आज़माने के लिए कुछ समय बाद भेजा जा सकता है. इससे यह पक्का करने में मदद मिलती है कि उपयोगकर्ता जो भी भेजना चाहता है वह असल में भेजा जाए.

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, बैकग्राउंड सिंक की सुविधा का इस्तेमाल करता है, ताकि खराब इंटरनेट कनेक्शन की वजह से पूरी न हो पाने वाली क्वेरी को सेव किया जा सके. साथ ही, उपयोगकर्ता के ऑनलाइन होने पर, उन्हें फिर से प्रोसेस किया जा सके. कार्रवाई पूरी होने के बाद, वेब पुश नोटिफ़िकेशन की मदद से, उपयोगकर्ता को नतीजा बताया जाता है:

डायग्राम में एक पेज दिखाया गया है, जो सर्विस वर्कर को पोर्ट करने के लिए इस्तेमाल कर रहा है. इससे दो-तरफ़ा बातचीत हो रही है.

बैकग्राउंड फ़ेच

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 74.
  • Edge: 79.
  • Firefox: यह सुविधा काम नहीं करती.
  • Safari: समर्थित नहीं.

सोर्स

मैसेज भेजने या कैश मेमोरी में सेव करने के लिए यूआरएल की सूची बनाने जैसे छोटे कामों के लिए, अब तक बताए गए विकल्प एक अच्छा विकल्प हैं. अगर टास्क पूरा होने में बहुत ज़्यादा समय लगता है, तो ब्राउज़र सेवा वर्कर्स को बंद कर देगा. ऐसा न करने पर, उपयोगकर्ता की निजता और बैटरी को खतरा हो सकता है.

बैकग्राउंड फ़ेच एपीआई की मदद से, आप सर्विस वर्कर के लिए कोई लंबा टास्क डाउनलोड कर सकते हैं. जैसे, फ़िल्में, पॉडकास्ट या गेम के लेवल डाउनलोड करना.

पेज से सर्विस वर्कर से संपर्क करने के लिए, 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}%`);
});
डायग्राम में, दोतरफ़ा कम्यूनिकेशन सेट अप करने के लिए, पेज को सेवा वर्कर को पोर्ट पास करते हुए दिखाया गया है.
डाउनलोड की प्रोग्रेस दिखाने के लिए, यूज़र इंटरफ़ेस (यूआई) को अपडेट किया गया है (बाईं ओर). सर्विस वर्कर का धन्यवाद, सभी टैब बंद होने (दाएं) होने पर, कार्रवाई जारी रह सकती है.

अगले चरण

इस गाइड में, हमने पेज और सेवा वर्कर्स के बीच बातचीत के सबसे सामान्य मामले (दोतरफ़ा बातचीत) के बारे में बताया है.

कई बार, किसी व्यक्ति को जवाब पाने के बिना ही, दूसरे व्यक्ति से बातचीत करने के लिए सिर्फ़ एक कॉन्टेक्स्ट की ज़रूरत पड़ सकती है. अपने पेजों पर, सेवा वर्कर से और सेवा वर्कर पर एकतरफ़ा तरीके लागू करने के तरीके के बारे में जानने के लिए, यहां दी गई गाइड देखें. इनमें इस्तेमाल के उदाहरण और प्रोडक्शन के उदाहरण भी शामिल हैं:

  • कैश मेमोरी में सेव करने के लिए ज़रूरी गाइड: पेज से किसी सर्विस वर्कर को कॉल करके, संसाधनों को पहले से कैश मेमोरी में सेव करना. उदाहरण के लिए, पहले से लोड करने की सुविधा के दौरान.
  • ब्रॉडकास्ट अपडेट: ज़रूरी अपडेट के बारे में जानकारी देने के लिए सर्विस वर्कर के पेज पर कॉल किया जा रहा है (उदाहरण के लिए, वेब ऐप्लिकेशन का नया वर्शन उपलब्ध है).