सामान्य सूचना पैटर्न

हम वेब पर पुश नोटिफ़िकेशन की सुविधा लागू करने के कुछ सामान्य पैटर्न देखेंगे.

इसके लिए, आपको सेवा वर्कर में उपलब्ध कुछ अलग-अलग एपीआई का इस्तेमाल करना होगा.

सूचना बंद होने का इवेंट

पिछले सेक्शन में, हमने notificationclick इवेंट को सुनने का तरीका देखा था.

notificationclose इवेंट भी होता है.यह तब ट्रिगर होता है, जब उपयोगकर्ता आपकी किसी सूचना को खारिज करता है. इसका मतलब है कि सूचना पर क्लिक करने के बजाय, उपयोगकर्ता क्रॉस पर क्लिक करता है या सूचना को स्वाइप करके हटा देता है.

आम तौर पर, इस इवेंट का इस्तेमाल आंकड़ों के लिए किया जाता है, ताकि सूचनाओं के साथ उपयोगकर्ता की दिलचस्पी को ट्रैक किया जा सके.

self.addEventListener('notificationclose', function (event) {
  const dismissedNotification = event.notification;

  const promiseChain = notificationCloseAnalytics();
  event.waitUntil(promiseChain);
});

सूचना में डेटा जोड़ना

पुश मैसेज मिलने पर, आम तौर पर ऐसा डेटा मिलता है जो सिर्फ़ तब काम का होता है, जब उपयोगकर्ता ने सूचना पर क्लिक किया हो. उदाहरण के लिए, वह यूआरएल जिस पर सूचना पर क्लिक करने पर जाना चाहिए.

किसी पुश इवेंट से डेटा लेने और उसे सूचना से जोड़ने का सबसे आसान तरीका यह है कि showNotification() में पास किए गए विकल्प ऑब्जेक्ट में data पैरामीटर जोड़ा जाए. जैसे:

const options = {
  body:
    'This notification has data attached to it that is printed ' +
    "to the console when it's clicked.",
  tag: 'data-notification',
  data: {
    time: new Date(Date.now()).toString(),
    message: 'Hello, World!',
  },
};
registration.showNotification('Notification with Data', options);

क्लिक हैंडलर में, डेटा को event.notification.data से ऐक्सेस किया जा सकता है.

const notificationData = event.notification.data;
console.log('');
console.log('The notification data has the following parameters:');
Object.keys(notificationData).forEach((key) => {
  console.log(`  ${key}: ${notificationData[key]}`);
});
console.log('');

विंडो खोलना

किसी सूचना का जवाब देने के लिए, आम तौर पर किसी खास यूआरएल की विंडो / टैब खोला जाता है. हम ऐसा clients.openWindow() एपीआई की मदद से कर सकते हैं.

अपने notificationclick इवेंट में, हम कुछ ऐसा कोड चलाएंगे:

const examplePage = '/demos/notification-examples/example-page.html';
const promiseChain = clients.openWindow(examplePage);
event.waitUntil(promiseChain);

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

किसी मौजूदा विंडो पर फ़ोकस करना

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

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

पिछले उदाहरण को ध्यान में रखते हुए, हम कोड में बदलाव करेंगे, ताकि यह देखा जा सके कि /demos/notification-examples/example-page.html पहले से खुला है या नहीं.

const urlToOpen = new URL(examplePage, self.location.origin).href;

const promiseChain = clients
  .matchAll({
    type: 'window',
    includeUncontrolled: true,
  })
  .then((windowClients) => {
    let matchingClient = null;

    for (let i = 0; i < windowClients.length; i++) {
      const windowClient = windowClients[i];
      if (windowClient.url === urlToOpen) {
        matchingClient = windowClient;
        break;
      }
    }

    if (matchingClient) {
      return matchingClient.focus();
    } else {
      return clients.openWindow(urlToOpen);
    }
  });

event.waitUntil(promiseChain);

आइए, कोड को सिलसिलेवार तरीके से देखते हैं.

सबसे पहले, हम यूआरएल एपीआई का इस्तेमाल करके, अपने उदाहरण वाले पेज को पार्स करते हैं. यह एक आसान तरीका है, जिसे मैंने जेफ़ पॉस्निक से सीखा है. location ऑब्जेक्ट के साथ new URL() को कॉल करने पर, अगर दी गई स्ट्रिंग रिलेटिव है, तो एक पूर्ण यूआरएल दिखेगा. इसका मतलब है कि /, https://example.com/ हो जाएगा.

हम यूआरएल को एब्सोलूट बनाते हैं, ताकि हम बाद में इसे विंडो के यूआरएल से मैच कर सकें.

const urlToOpen = new URL(examplePage, self.location.origin).href;

इसके बाद, हमें WindowClient ऑब्जेक्ट की सूची मिलती है. यह सूची, फ़िलहाल खुले टैब और विंडो की होती है. (ध्यान रखें कि ये टैब सिर्फ़ आपके ऑरिजिन के लिए हैं.)

const promiseChain = clients.matchAll({
  type: 'window',
  includeUncontrolled: true,
});

matchAll में दिए गए विकल्पों से ब्राउज़र को पता चलता है कि हमें सिर्फ़ "विंडो" टाइप के क्लाइंट खोजने हैं. इसका मतलब है कि सिर्फ़ टैब और विंडो खोजें और वेब वर्कर्स को बाहर रखें. includeUncontrolled की मदद से, हम आपके ऑरिजिन के उन सभी टैब को खोज सकते हैं जिन्हें मौजूदा सर्विस वर्कर कंट्रोल नहीं करता. जैसे, यह कोड चलाने वाला सर्विस वर्कर. आम तौर पर, matchAll() को कॉल करते समय, आपको हमेशा includeUncontrolled को सही रखना होगा.

हम रिटर्न किए गए प्रॉमिस को promiseChain के तौर पर कैप्चर करते हैं, ताकि हम बाद में इसे event.waitUntil() में पास कर सकें. इससे, हमारे सेवा वर्कर को चालू रखा जा सकता है.

जब matchAll() प्रॉमिस पूरा हो जाता है, तो हम विंडो क्लाइंट के ज़रिए फिर से शुरू करते हैं और उनके यूआरएल की तुलना उस यूआरएल से करते हैं जिसे हमें खोलना है. अगर हमें कोई मैच मिलता है, तो हम उस क्लाइंट पर फ़ोकस करते हैं. इससे, उपयोगकर्ताओं का ध्यान उस विंडो पर जाएगा. फ़ोकस करने के लिए, matchingClient.focus() कॉल का इस्तेमाल किया जाता है.

अगर हमें मैच होने वाला कोई क्लाइंट नहीं मिलता है, तो हम पिछले सेक्शन की तरह ही एक नई विंडो खोलते हैं.

.then((windowClients) => {
  let matchingClient = null;

  for (let i = 0; i < windowClients.length; i++) {
    const windowClient = windowClients[i];
    if (windowClient.url === urlToOpen) {
      matchingClient = windowClient;
      break;
    }
  }

  if (matchingClient) {
    return matchingClient.focus();
  } else {
    return clients.openWindow(urlToOpen);
  }
});

सूचनाओं को मर्ज करना

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

हालांकि, Notification API का इस्तेमाल करके सूचनाओं को छोटा किया जा सकता है. किसी चैट ऐप्लिकेशन के बारे में सोचें. हो सकता है कि डेवलपर, नई सूचना में सिर्फ़ नया मैसेज दिखाने के बजाय, "आपके पास मैट से दो मैसेज हैं" जैसा मैसेज दिखाना चाहे.

ऐसा करने के लिए, registration.getNotifications() API का इस्तेमाल करें. इससे आपको अपने वेब ऐप्लिकेशन के लिए, फ़िलहाल दिख रही सभी सूचनाओं का ऐक्सेस मिलता है. इसके अलावा, मौजूदा सूचनाओं में अन्य तरीकों से भी बदलाव किया जा सकता है.

आइए, चैट के उदाहरण को लागू करने के लिए, इस एपीआई का इस्तेमाल करने का तरीका देखें.

मान लें कि हमारे चैट ऐप्लिकेशन में, हर सूचना में कुछ डेटा होता है, जिसमें उपयोगकर्ता का नाम शामिल होता है.

सबसे पहले, हम किसी खास उपयोगकर्ता नाम वाले उपयोगकर्ता के लिए, खुली हुई सूचनाएं ढूंढना चाहेंगे. हमें registration.getNotifications() मिलेंगे और हम उन पर लूप करेंगे और किसी खास उपयोगकर्ता नाम के लिए notification.data की जांच करेंगे:

const promiseChain = registration.getNotifications().then((notifications) => {
  let currentNotification;

  for (let i = 0; i < notifications.length; i++) {
    if (notifications[i].data && notifications[i].data.userName === userName) {
      currentNotification = notifications[i];
    }
  }

  return currentNotification;
});

इसके बाद, इस सूचना को नई सूचना से बदलें.

इस फ़र्ज़ी मैसेज ऐप्लिकेशन में, हम अपनी नई सूचना के डेटा में एक संख्या जोड़कर, नए मैसेज की संख्या को ट्रैक करेंगे. साथ ही, हर नई सूचना के साथ इस संख्या को बढ़ाएंगे.

.then((currentNotification) => {
  let notificationTitle;
  const options = {
    icon: userIcon,
  }

  if (currentNotification) {
    // We have an open notification, let's do something with it.
    const messageCount = currentNotification.data.newMessageCount + 1;

    options.body = `You have ${messageCount} new messages from ${userName}.`;
    options.data = {
      userName: userName,
      newMessageCount: messageCount
    };
    notificationTitle = `New Messages from ${userName}`;

    // Remember to close the old notification.
    currentNotification.close();
  } else {
    options.body = `"${userMessage}"`;
    options.data = {
      userName: userName,
      newMessageCount: 1
    };
    notificationTitle = `New Message from ${userName}`;
  }

  return registration.showNotification(
    notificationTitle,
    options
  );
});

अगर फ़िलहाल कोई सूचना दिख रही है, तो हम मैसेज की संख्या बढ़ा देते हैं और सूचना का टाइटल और मुख्य हिस्सा तय करते हैं. अगर कोई सूचना नहीं है, तो हम newMessageCount को 1 पर सेट करके एक नई सूचना बनाते हैं.

इससे पहला मैसेज कुछ ऐसा दिखेगा:

मर्ज किए बिना पहली सूचना.

दूसरी सूचना मिलने पर, सूचनाएं इस तरह दिखेंगी:

मर्ज करने के बाद मिली दूसरी सूचना.

इस तरीके की सबसे अच्छी बात यह है कि अगर आपके उपयोगकर्ता को एक के ऊपर एक सूचनाएं दिखती हैं, तो उन्हें सूचना को नए मैसेज से बदलने के बजाय, एक साथ कई सूचनाएं दिखने से बेहतर अनुभव मिलेगा.

नियम का अपवाद

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

अपने पुश इवेंट में, विंडो क्लाइंट की जांच करके और फ़ोकस की गई विंडो ढूंढकर, यह देखा जा सकता है कि आपको कोई सूचना दिखानी है या नहीं.

सभी विंडो पाने और फ़ोकस की गई विंडो ढूंढने का कोड ऐसा दिखता है:

function isClientFocused() {
  return clients
    .matchAll({
      type: 'window',
      includeUncontrolled: true,
    })
    .then((windowClients) => {
      let clientIsFocused = false;

      for (let i = 0; i < windowClients.length; i++) {
        const windowClient = windowClients[i];
        if (windowClient.focused) {
          clientIsFocused = true;
          break;
        }
      }

      return clientIsFocused;
    });
}

हम अपने सभी विंडो क्लाइंट पाने के लिए, clients.matchAll() का इस्तेमाल करते हैं. इसके बाद, हम focused पैरामीटर की जांच करते हुए, उन पर लूप लगाते हैं.

हम अपने पुश इवेंट में इस फ़ंक्शन का इस्तेमाल करके यह तय करेंगे कि हमें कोई सूचना दिखानी है या नहीं:

const promiseChain = isClientFocused().then((clientIsFocused) => {
  if (clientIsFocused) {
    console.log("Don't need to show a notification.");
    return;
  }

  // Client isn't focused, we need to show a notification.
  return self.registration.showNotification('Had to show a notification.');
});

event.waitUntil(promiseChain);

किसी पुश इवेंट से किसी पेज को मैसेज भेजना

हमने देखा है कि अगर उपयोगकर्ता फ़िलहाल आपकी साइट पर है, तो सूचना दिखाने से बचा जा सकता है. हालांकि, अगर आपको उपयोगकर्ता को यह बताना है कि कोई इवेंट हुआ है, लेकिन सूचना भेजना ज़रूरी नहीं है, तो क्या करें?

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

मान लें कि हमें कोई पुश मैसेज मिला है और हमने यह जांच कर ली है कि फ़िलहाल हमारा वेब ऐप्लिकेशन फ़ोकस में है, तो हम हर खुले पेज पर "मैसेज पोस्ट" कर सकते हैं. जैसे:

const promiseChain = isClientFocused().then((clientIsFocused) => {
  if (clientIsFocused) {
    windowClients.forEach((windowClient) => {
      windowClient.postMessage({
        message: 'Received a push message.',
        time: new Date().toString(),
      });
    });
  } else {
    return self.registration.showNotification('No focused windows', {
      body: 'Had to show a notification instead of messaging each page.',
    });
  }
});

event.waitUntil(promiseChain);

हम हर पेज पर, मैसेज इवेंट के लिसनर को जोड़कर मैसेज सुनते हैं:

navigator.serviceWorker.addEventListener('message', function (event) {
  console.log('Received a message from service worker: ', event.data);
});

इस मैसेज लिसनर में, अपनी पसंद के मुताबिक कुछ भी किया जा सकता है. जैसे, अपने पेज पर कस्टम यूज़र इंटरफ़ेस (यूआई) दिखाना या मैसेज को पूरी तरह से अनदेखा करना.

यह भी ध्यान देने वाली बात है कि अगर आपने अपने वेब पेज में मैसेज सुनने वाला कोई लिसनर तय नहीं किया है, तो सेवा वर्कर से मिलने वाले मैसेज कुछ भी नहीं करेंगे.

किसी पेज को कैश मेमोरी में सेव करना और विंडो खोलना

इस गाइड में एक स्थिति के बारे में नहीं बताया गया है, लेकिन इस पर चर्चा करना ज़रूरी है. इस स्थिति में, वेब पेजों को कैश मेमोरी में सेव करके, अपने वेब ऐप्लिकेशन के यूज़र एक्सपीरियंस को बेहतर बनाया जा सकता है. ऐसा उन वेब पेजों के लिए किया जा सकता है जिन पर आपके हिसाब से, उपयोगकर्ता आपकी सूचना पर क्लिक करने के बाद जाएंगे.

इसके लिए, fetch इवेंट को हैंडल करने के लिए, आपके पास सेवा वर्कर का सेट-अप होना चाहिए. हालांकि, अगर आपने fetch इवेंट लिसनर लागू किया है, तो पक्का करें कि आपने push इवेंट में इसका फ़ायदा लिया हो. इसके लिए, सूचना दिखाने से पहले, आपको पेज और ऐसेट को कैश मेमोरी में सेव करना होगा.

ब्राउज़र के साथ काम करना

notificationclose इवेंट

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

  • Chrome: 50.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 16.

सोर्स

Clients.openWindow()

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

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

सोर्स

ServiceWorkerRegistration.getNotifications()

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

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

सोर्स

clients.matchAll()

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

  • Chrome: 42.
  • Edge: 17.
  • Firefox: 54.
  • Safari: 11.1.

सोर्स

ज़्यादा जानकारी के लिए, सेवा वर्कर के बारे में जानकारी देने वाली यह पोस्ट देखें.

आगे क्या करना है

कोड लैब