पेश है बैकग्राउंड में डेटा फ़ेच करने की सुविधा

जेक आर्चिबाल्ड
जेक आर्किबाल्ड

हमने 2015 में बैकग्राउंड सिंक की सुविधा शुरू की. इसकी मदद से, सर्विस वर्कर तब तक काम करना बंद कर सकता है, जब तक उपयोगकर्ता के पास इंटरनेट कनेक्शन नहीं हो जाता. इसका मतलब है कि उपयोगकर्ता मैसेज टाइप कर सकता है, 'भेजें' पर क्लिक कर सकता है और साइट से बाहर निकल सकता है. साथ ही, उपयोगकर्ता यह जानते हुए भी साइट छोड़ सकता है कि मैसेज अब भेजा जाएगा या उसके पास कनेक्टिविटी होगी.

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

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

बैकग्राउंड फ़ेच करने की सुविधा, Chrome 74 के बाद से डिफ़ॉल्ट रूप से उपलब्ध है.

यहां दो मिनट का एक डेमो दिया गया है, जिसमें बैकग्राउंड को फ़ेच करने के बजाय चीज़ों की पारंपरिक स्थिति दिखाई गई है:

खुद डेमो आज़माएं और कोड ब्राउज़ करें.

यह सुविधा कैसे काम करती है

बैकग्राउंड फ़ेच करने की सुविधा इस तरह काम करती है:

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

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

कुछ प्लैटफ़ॉर्म (जैसे कि Android) पर, पहले चरण के बाद ब्राउज़र बंद हो सकता है, क्योंकि ब्राउज़र, फ़ेच करने की प्रोसेस को ऑपरेटिंग सिस्टम में बंद कर सकता है.

अगर उपयोगकर्ता, ऑफ़लाइन होने पर डाउनलोड शुरू करता है या डाउनलोड के दौरान ऑफ़लाइन हो जाता है, तो बैकग्राउंड फ़ेच रुक जाएगा और बाद में फिर से शुरू होगा.

एपीआई

सुविधा की पहचान

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

if ('BackgroundFetchManager' in self) {
  // This browser supports Background 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,
  });
});

backgroundFetch.fetch तीन तर्क लेता है:

पैरामीटर
id string
इस बैकग्राउंड फ़ेच की पहचान करता है.

अगर आईडी, बैकग्राउंड में डेटा फ़ेच करने की मौजूदा सुविधा से मेल खाता है, तो backgroundFetch.fetch अस्वीकार कर दिया जाएगा.

requests Array<Request|string>
वे चीज़ें जो फ़ेच की जा सकती हैं. स्ट्रिंग को यूआरएल के तौर पर माना जाएगा और उन्हें new Request(theString) के ज़रिए, Request में बदल दिया जाएगा.

अन्य ऑरिजिन से चीज़ें फ़ेच की जा सकती हैं. हालांकि, इसके लिए ज़रूरी है कि संसाधनों में इन्हें सीओआरएस की मदद से अनुमति दी गई हो.

ध्यान दें: फ़िलहाल, Chrome में ऐसे अनुरोधों की सुविधा नहीं है जिनके लिए सीओआरएस प्रीफ़्लाइट की ज़रूरत हो.

options एक ऑब्जेक्ट जिसमें नीचे दी गई चीज़ें शामिल हो सकती हैं:
options.title string
ब्राउज़र की प्रोग्रेस के साथ दिखाने के लिए टाइटल.
options.icons Array<IconDefinition>
`src`, `size`, और `type` वाले ऑब्जेक्ट का कलेक्शन.
options.downloadTotal number
रिस्पॉन्स के मुख्य हिस्से का कुल साइज़ (अन-gज़िप किए जाने के बाद).

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

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

backgroundFetch.fetch ऐसा प्रॉमिस देता है जो BackgroundFetchRegistration के साथ रिज़ॉल्व हो जाता है. मैं इस बारे में बाद में बताऊँगी. अगर उपयोगकर्ता ने डाउनलोड से ऑप्ट आउट किया है या दिया गया कोई पैरामीटर अमान्य है, तो प्रॉमिस अस्वीकार कर दिया जाता है.

एक बैकग्राउंड फ़ेच के लिए कई अनुरोध करने से, आप कई चीज़ों को एक साथ इस्तेमाल कर सकते हैं. उदाहरण के लिए, किसी फ़िल्म को सैकड़ों संसाधनों (MPEG-DASH के साथ आम तौर पर) में बांटा जा सकता है और इसमें इमेज जैसे अतिरिक्त संसाधन शामिल किए जा सकते हैं. गेम के एक लेवल को कई JavaScript, इमेज, और ऑडियो संसाधनों में बांटा जा सकता है. हालांकि, उपयोगकर्ता के लिए इसका मतलब सिर्फ़ "फ़िल्म" या "लेवल" है.

मौजूदा बैकग्राउंड फ़ेच किया जा रहा है

बैकग्राउंड फ़ेच करने की मौजूदा सुविधा इस तरह से ली जा सकती है:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

...अपने पसंद के बैकग्राउंड फ़ेच का id पास करके. अगर उस आईडी के साथ बैकग्राउंड फ़ेच कोई चालू नहीं है, तो get undefined दिखाता है.

बैकग्राउंड फ़ेच को रजिस्टर होने के बाद से "चालू" माना जाता है. ऐसा तब तक होता है, जब तक कि वह काम नहीं करता, काम नहीं करता या रद्द कर दिया जाता है.

getIds का इस्तेमाल करके, बैकग्राउंड के सभी चालू फ़ेच की सूची देखी जा सकती है:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

बैकग्राउंड फ़ेच करने के लिए रजिस्ट्रेशन

BackgroundFetchRegistration (ऊपर दिए गए उदाहरणों में bgFetch) के बारे में यहां बताया गया है:

प्रॉपर्टी
id string
बैकग्राउंड में फ़ेच करने का आईडी.
uploadTotal number
सर्वर को भेजी जाने वाली बाइट की संख्या.
uploaded number
भेजे गए बाइट की संख्या.
downloadTotal number
बैकग्राउंड में फ़ेच करने की सुविधा को रजिस्टर किए जाने पर दी गई वैल्यू या शून्य.
downloaded number
पूरे हुए बाइट की संख्या.

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

result

इनमें से कोई एक:

  • "" - बैकग्राउंड में फ़ेच करने की सुविधा चालू है, इसलिए अभी तक कोई नतीजा नहीं मिला है.
  • "success" - बैकग्राउंड फ़ेच किया गया.
  • "failure" - बैकग्राउंड फ़ेच नहीं किया जा सका. यह वैल्यू सिर्फ़ तब दिखती है, जब बैकग्राउंड फ़ेच पूरी तरह से काम नहीं करता. ऐसा इसलिए, क्योंकि ब्राउज़र में फिर से कोशिश नहीं की जा सकती.
failureReason

इनमें से कोई एक:

  • "" - बैकग्राउंड फ़ेच नहीं किया जा सका.
  • "aborted" – बैकग्राउंड फ़ेच करने की प्रोसेस को उपयोगकर्ता ने रद्द कर दिया या abort() को कॉल किया गया.
  • "bad-status" - किसी एक जवाब की स्थिति 'ठीक नहीं है' के तौर पर मिली थी, जैसे कि 404.
  • "fetch-error" - इनमें से कोई एक फ़ेच किसी दूसरी वजह से नहीं हो सका. जैसे, सीओआरएस, MIX, अमान्य अधूरा जवाब या फ़ेच करने में नेटवर्क की ऐसी सामान्य गड़बड़ी जिसके लिए फिर से कोशिश नहीं की जा सकती.
  • "quota-exceeded" - बैकग्राउंड में फ़ेच करने के दौरान स्टोरेज कोटा पूरा हो गया.
  • "download-total-exceeded" - आपने जो `downloadTotal` का इस्तेमाल किया है वह तय सीमा से ज़्यादा है.
recordsAvailable boolean
क्या दिए गए अनुरोध/जवाब ऐक्सेस किए जा सकते हैं?

इसके गलत होने पर match और matchAll का इस्तेमाल नहीं किया जा सकता.

तरीके
abort() Promise<boolean>
दिखाता है या बैकग्राउंड के फ़ेच होने की प्रोसेस को रद्द करता है.

अगर फ़ेच रद्द कर दिया गया था, तो दिखाया गया प्रॉमिस सही के साथ रिज़ॉल्व हो जाता है.

matchAll(request, opts) Promise<Array<BackgroundFetchRecord>>
अनुरोध और जवाब पाएं.

यहां दिए गए आर्ग्युमेंट और कैश मेमोरी एपीआई एक जैसे हैं. आर्ग्युमेंट के बिना कॉल करने से, सभी रिकॉर्ड के लिए प्रॉमिस मिलता है.

ज़्यादा जानकारी के लिए नीचे देखें.

match(request, opts) यह वैल्यू Promise<BackgroundFetchRecord>
जैसा कि ऊपर मौजूद है, लेकिन यह वैल्यू पहले मैच के साथ रिज़ॉल्व हो जाती है.
इवेंट
progress uploaded, downloaded, result या failureReason में से किसी भी बदलाव पर सक्रिय होता है.

प्रोग्रेस ट्रैक हो रहा है

ऐसा progress इवेंट के ज़रिए किया जा सकता है. याद रखें कि आपने जो भी वैल्यू दी है, downloadTotal वही वैल्यू है. अगर आपने कोई वैल्यू नहीं दी है, तो 0.

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}%`);
});

अनुरोध और जवाब फ़ेच किए जा रहे हैं

bgFetch.match('/ep-5.mp3').then(async (record) => {
  if (!record) {
    console.log('No record found');
    return;
  }

  console.log(`Here's the request`, record.request);
  const response = await record.responseReady;
  console.log(`And here's the response`, response);
});

record एक BackgroundFetchRecord है और यह ऐसा दिखता है:

प्रॉपर्टी
request Request
वह अनुरोध जो दिया गया है.
responseReady Promise<Response>
फ़ेच किया गया जवाब.

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

सर्विस वर्कर के इवेंट

इवेंट
backgroundfetchsuccess सारा डेटा फ़ेच किया गया.
backgroundfetchfailure एक या उससे ज़्यादा फ़ेच नहीं किए जा सके.
backgroundfetchabort एक या उससे ज़्यादा फ़ेच नहीं किए जा सके.

यह सुविधा सिर्फ़ तब काम आती है, जब आपको मिलते-जुलते डेटा को हटाना हो.

backgroundfetchclick उपयोगकर्ता ने डाउनलोड प्रोग्रेस यूज़र इंटरफ़ेस (यूआई) पर क्लिक किया.

इवेंट ऑब्जेक्ट में ये चीज़ें होती हैं:

प्रॉपर्टी
registration BackgroundFetchRegistration
तरीके
updateUI({ title, icons }) इससे आपके शुरू में सेट किए गए टाइटल/आइकॉन को बदलने में मदद मिलती है. हालांकि, ऐसा करना ज़रूरी नहीं है. हालांकि, इसकी मदद से ज़रूरत पड़ने पर ज़्यादा जानकारी दी जा सकती है. backgroundfetchsuccess और backgroundfetchfailure इवेंट के दौरान, ऐसा सिर्फ़ *एक बार* किया जा सकता है.

सफलता/असफलता पर प्रतिक्रिया देना

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

अगर बैकग्राउंड फ़ेच पूरा हो जाता है, तो आपके सर्विस वर्कर को backgroundfetchsuccess इवेंट मिलेगा और event.registration बैकग्राउंड फ़ेच रजिस्ट्रेशन होगा.

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

जैसा कि ज़्यादातर सर्विस वर्कर इवेंट के साथ होता है, event.waitUntil का इस्तेमाल करें, ताकि सर्विस वर्कर को पता चल सके कि इवेंट कब पूरा होगा.

उदाहरण के लिए, आपके सर्विस वर्कर में:

addEventListener('backgroundfetchsuccess', (event) => {
  const bgFetch = event.registration;

  event.waitUntil(async function() {
    // Create/open a cache.
    const cache = await caches.open('downloads');
    // Get all the records.
    const records = await bgFetch.matchAll();
    // Copy each request/response across.
    const promises = records.map(async (record) => {
      const response = await record.responseReady;
      await cache.put(record.request, response);
    });

    // Wait for the copying to complete.
    await Promise.all(promises);

    // Update the progress notification.
    event.updateUI({ title: 'Episode 5 ready to listen!' });
  }());
});

ऐसा हो सकता है कि किसी गड़बड़ी की वजह से 404 कोड वाला मैसेज दिख रहा हो, जो आपके लिए ज़रूरी न हो. इसलिए, ऊपर बताए गए तरीके से, कुछ जवाबों को कैश मेमोरी में कॉपी करना अब भी फ़ायदेमंद हो सकता है.

क्लिक करने पर प्रतिक्रिया दे रही है

यूज़र इंटरफ़ेस (यूआई) पर क्लिक करने के बाद, उपयोगकर्ता को डाउनलोड की प्रोग्रेस और नतीजे दिख रहे हैं. सर्विस वर्कर में backgroundfetchclick इवेंट से, आपको इस पर प्रतिक्रिया देने का विकल्प मिलता है. जैसा कि event.registration से ऊपर है, बैकग्राउंड रजिस्ट्रेशन फ़ेच होगा.

इस इवेंट के साथ ऐसा करने के लिए एक विंडो खोलें:

addEventListener('backgroundfetchclick', (event) => {
  const bgFetch = event.registration;

  if (bgFetch.result === 'success') {
    clients.openWindow('/latest-podcasts');
  } else {
    clients.openWindow('/download-progress');
  }
});

अन्य संसाधन

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