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

मैट गौंट

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

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

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

पिछले सेक्शन में, हमने देखा कि हम 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);
  }
});

नोटिफ़िकेशन मर्ज करना

हमने देखा कि सूचना में टैग जोड़ने से, उसी टैग वाली कोई भी मौजूदा सूचना बदल जाती है.

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

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

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

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

हम सबसे पहले यह पता करेंगे कि किसी खास उपयोगकर्ता नाम वाले उपयोगकर्ता को दी जाने वाली कोई सूचना है या नहीं. हम 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
  );
});

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

ऐसा करने पर, पहला मैसेज ऐसा दिखेगा:

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

एक दूसरी सूचना से सूचनाओं को इस तरह छोटा कर दिया जाएगा:

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

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

नियम का अपवाद

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

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

सभी विंडो पाने और फ़ोकस की गई विंडो खोजने के लिए कोड कुछ ऐसा दिखता है:

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 इवेंट

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

  • 50
  • 17
  • 44
  • 16

सोर्स

Clients.openWindow()

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

  • 40
  • 17
  • 44
  • 11.1

सोर्स

ServiceWorkerRegistration.getNotifications()

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

  • 40
  • 17
  • 44
  • 16

सोर्स

clients.matchAll()

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

  • 42
  • 17
  • 54
  • 11.1

सोर्स

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

आगे कहां जाना है

कोड लैब