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

Andrew Guan
Andrew Guan

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

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

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

अंतर:

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

Broadcast Channel API

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

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

Client API

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

  • Chrome: 40.
  • Edge: 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: यह सुविधा काम नहीं करती.

सोर्स

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

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

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

अगले चरण

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

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