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

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

अंतर:

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

Broadcast Channel API

Browser Support

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

Source

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

Browser Support

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1.

Source

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

मैसेज चैनल

Browser Support

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

Source

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

चैनल को शुरू करने के लिए, पेज एक 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 की सुविधा सभी मुख्य ब्राउज़र पर काम करती है.

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

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

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

Browser Support

  • Chrome: 49.
  • Edge: 79.
  • Firefox: not supported.
  • Safari: not supported.

Source

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

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

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

Browser Support

  • Chrome: 74.
  • Edge: 79.
  • Firefox: not supported.
  • Safari: not supported.

Source

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

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

अगले चरण

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

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