स्ट्रीम के साथ ज़्यादा तेज़ी से कई पेज वाले ऐप्लिकेशन

इन दिनों, वेबसाइटें—या वेब ऐप्लिकेशन, इन दोनों में से किसी एक नेविगेशन स्कीम का इस्तेमाल करना पसंद करती हैं:

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

दोनों ही रणनीति के फ़ायदों की जानकारी उनके समर्थकों ने दी है:

  • ब्राउज़र डिफ़ॉल्ट रूप से जो नेविगेशन स्कीम देते हैं वह लंबे समय तक काम करती है, क्योंकि रूट के लिए JavaScript को ऐक्सेस करने की ज़रूरत नहीं होती. JavaScript के ज़रिए मार्कअप की क्लाइंट रेंडरिंग भी महंगी हो सकती है. इसका मतलब यह है कि कम कीमत वाले डिवाइसों पर ऐसी स्थिति आ सकती है जिसमें कॉन्टेंट दिखने में देरी हो. इसकी वजह यह है कि डिवाइस, कॉन्टेंट उपलब्ध कराने वाली स्क्रिप्ट को प्रोसेस करने से रोक देता है.
  • वहीं दूसरी ओर, एक पेज के ऐप्लिकेशन (एसपीए), लोड होने के बाद उन्हें तेज़ी से नेविगेट करने की सुविधा देते हैं. किसी पूरी तरह से नए दस्तावेज़ के लिए दस्तावेज़ अनलोड करने के लिए, ब्राउज़र पर निर्भर रहने के बजाय (और हर नेविगेशन के लिए इसे दोहराने के बजाय), वे एक तेज़ और ज़्यादा "ऐप्लिकेशन जैसा" अनुभव दे सकते हैं अनुभव—भले ही उसके लिए JavaScript को काम करना ज़रूरी हो.

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

सर्विस वर्कर में एचटीएमएल रिस्पॉन्स को स्ट्रीम क्यों करना चाहिए?

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

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

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

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

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

किसी सामान्य वेब पेज का विश्लेषण करना

स्ट्रक्चर के हिसाब से, वेबसाइटों के हर पेज पर एक जैसे एलिमेंट होते हैं.का तरीका है. पेज के एलिमेंट आम तौर पर कुछ इस तरह से दिखते हैं:

  • हेडर.
  • सामग्री.
  • फ़ुटर.

web.dev को उदाहरण के तौर पर इस्तेमाल करने पर, सामान्य एलिमेंट का ब्रेकडाउन इस तरह दिखता है:

web.dev वेबसाइट पर, आम तौर पर इस्तेमाल होने वाली चीज़ों के बारे में जानकारी. रिपोर्ट में मौजूद कॉमन एरिया 'हेडर', 'कॉन्टेंट', और 'फ़ुटर' के तौर पर मार्क किए गए हैं.

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

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

इसके बाद, workbox-streams के ज़रिए Streams API का इस्तेमाल करके, हम इन सभी हिस्सों को एक साथ जोड़ सकते हैं और नेविगेशन के अनुरोधों का तुरंत जवाब दे सकते हैं. ऐसा करते हुए, हम नेटवर्क से ज़रूरी कम से कम मार्कअप का अनुरोध करते हैं.

स्ट्रीमिंग सर्विस वर्कर बनाना

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

अपनी वेबसाइट को कुछ हिस्सों में बांटना

स्ट्रीमिंग सर्विस वर्कर को लिखना शुरू करने से पहले, आपको ये तीन काम करने होंगे:

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

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

स्ट्रीमिंग सर्विस वर्कर को कंपोज़ करना

अगर आपने workbox-streams मॉड्यूल इंस्टॉल नहीं किया है, तो फ़िलहाल आपने जो भी Workbox मॉड्यूल इंस्टॉल किए हैं उनके साथ-साथ आपको ऐसा करना होगा. उदाहरण के लिए, इसमें ये पैकेज शामिल हैं:

npm i workbox-navigation-preload workbox-strategies workbox-routing workbox-precaching workbox-streams --save

यहां आपको नया सर्विस वर्कर बनाना होगा और हेडर और फ़ुटर के कुछ हिस्सों को पहले ही कैश मेमोरी में सेव करना होगा.

कुछ हिस्सों को पहले से कैश मेमोरी में सेव किया जा रहा है

आपको सबसे पहले अपने प्रोजेक्ट के रूट में sw.js (या जो भी फ़ाइल नाम आपको पसंद हो) बनाने वाला सर्विस वर्कर बनाना होगा. इसमें, आप इन चीज़ों से शुरुआत करेंगे:

// sw.js
import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {strategy as composeStrategies} from 'workbox-streams';

// Enable navigation preload for supporting browsers
navigationPreload.enable();

// Precache partials and some static assets
// using the InjectManifest method.
precacheAndRoute([
  // The header partial:
  {
    url: '/partial-header.php',
    revision: __PARTIAL_HEADER_HASH__
  },
  // The footer partial:
  {
    url: '/partial-footer.php',
    revision: __PARTIAL_FOOTER_HASH__
  },
  // The offline fallback:
  {
    url: '/offline.php',
    revision: __OFFLINE_FALLBACK_HASH__
  },
  ...self.__WB_MANIFEST
]);

// To be continued...

यह कोड कई काम करता है:

  1. यह सुविधा जिन ब्राउज़र पर काम करती है उनके लिए, नेविगेशन को पहले से लोड करने की सुविधा चालू करती है.
  2. हेडर और फ़ुटर मार्कअप को पहले से कैश मेमोरी में सेव करता है. इसका मतलब है कि हर पेज के लिए हेडर और फ़ुटर मार्कअप तुरंत मिल जाएंगे, क्योंकि नेटवर्क उन्हें ब्लॉक नहीं करेगा.
  3. injectManifest तरीके का इस्तेमाल करने वाले __WB_MANIFEST प्लेसहोल्डर में, स्टैटिक ऐसेट को प्रीकैश किया जाता है.

जवाब स्ट्रीम किए जा रहे हैं

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

// sw.js
import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {strategy as composeStrategies} from 'workbox-streams';

// ...
// Prior navigation preload and precaching code omitted...
// ...

// The strategy for retrieving content partials from the network:
const contentStrategy = new NetworkFirst({
  cacheName: 'content',
  plugins: [
    {
      // NOTE: This callback will never be run if navigation
      // preload is not supported, because the navigation
      // request is dispatched while the service worker is
      // booting up. This callback will only run if navigation
      // preload is _not_ supported.
      requestWillFetch: ({request}) => {
        const headers = new Headers();

        // If the browser doesn't support navigation preload, we need to
        // send a custom `X-Content-Mode` header for the back end to use
        // instead of the `Service-Worker-Navigation-Preload` header.
        headers.append('X-Content-Mode', 'partial');

        // Send the request with the new headers.
        // Note: if you're using a static site generator to generate
        // both full pages and content partials rather than a back end
        // (as this example assumes), you'll need to point to a new URL.
        return new Request(request.url, {
          method: 'GET',
          headers
        });
      },
      // What to do if the request fails.
      handlerDidError: async ({request}) => {
        return await matchPrecache('/offline.php');
      }
    }
  ]
});

// Concatenates precached partials with the content partial
// obtained from the network (or its fallback response).
const navigationHandler = composeStrategies([
  // Get the precached header markup.
  () => matchPrecache('/partial-header.php'),
  // Get the content partial from the network.
  ({event}) => contentStrategy.handle(event),
  // Get the precached footer markup.
  () => matchPrecache('/partial-footer.php')
]);

// Register the streaming route for all navigation requests.
registerRoute(({request}) => request.mode === 'navigate', navigationHandler);

// Your service worker can end here, or you can add more
// logic to suit your needs, such as runtime caching, etc.

इस कोड के तीन मुख्य हिस्से होते हैं, जो नीचे दी गई ज़रूरी शर्तें पूरी करते हैं:

  1. कॉन्टेंट क�� कुछ हिस्से के अनुरोधों को मैनेज करने के लिए, NetworkFirst रणनीति का इस्ते��ाल क������ ������ा है. इस रणनीति का इस्तेमाल करके, कैश मेमोरी के कस्टम नाम content में कॉन्टेंट के कुछ हिस्से शामिल करने के लिए जानकारी दी गई है. साथ ही, एक कस्टम प्लगिन भी शामिल किया गया है, जो यह मैनेज करता है कि नेविगेशन पहले से लोड करने की सुविधा पर काम न करने वाले ब्राउज़र के लिए, X-Content-Mode का अनुरोध हेडर सेट करना है या नहीं. इसलिए, यह Service-Worker-Navigation-Preload हेडर नहीं भेजता है. यह प्लगिन यह भी पता लगाता है कि किसी कॉन्टेंट के आखिरी हिस्से के कैश मेमोरी में सेव किए गए वर्शन को भेजना है या फिर मौजूदा अनुरोध के लिए, कैश मेमोरी में सेव किया गया कोई वर्शन सेव न होने पर, ऑफ़लाइन फ़ॉलबैक पेज भेजना है.
  2. workbox-streams में strategy तरीके का इस्तेमाल, नेटवर्क से अनुरोध किए गए कॉन्टेंट के साथ, पहले से कैश मेमोरी में सेव किए गए हेडर और फ़ुटर के कुछ हिस्सों को जोड़ने के लिए किया जाता है. workbox-streams में इसे composeStrategies कहा जाता है.
  3. नेविगेशन के अनुरोधों के लिए, registerRoute के ज़रिए पूरी स्कीम को व्यवस्थित किया गया है.

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

अगर आपकी वेबसाइट का कोई बैक एंड है

आपको याद होगा कि नेविगेशन प्रीलोड के चालू होने पर, ब्राउज़र true वैल्यू वाला एक Service-Worker-Navigation-Preload हेडर भेजता है. हालांकि, ऊपर दिए गए कोड सैंपल में, हमने इवेंट नेविगेशन के दौरान X-Content-Mode का कस्टम हेडर भेजा है. यह हेडर, ब्राउज़र में काम नहीं करता. बैक एंड में, इन हेडर की मौजूदगी के आधार पर रिस्पॉन्स को बदला जा सकता है. PHP बैक एंड में, दिए गए पेज के ��िए वह कुछ ऐसा दिखाई दे सकता है:

<?php
// Check if we need to render a content partial
$navPreloadSupported = isset($_SERVER['HTTP_SERVICE_WORKER_NAVIGATION_PRELOAD']) && $_SERVER['HTTP_SERVICE_WORKER_NAVIGATION_PRELOAD'] === 'true';
$partialContentMode = isset($_SERVER['HTTP_X_CONTENT_MODE']) && $_SERVER['HTTP_X_CONTENT_MODE'] === 'partial';
$isPartial = $navPreloadSupported || $partialContentMode;

// Figure out whether to render the header
if ($isPartial === false) {
  // Get the header include
  require_once($_SERVER['DOCUMENT_ROOT'] . '/includes/site-header.php');

  // Render the header
  siteHeader();
}

// Get the content include
require_once('./content.php');

// Render the content
content($isPartial);

// Figure out whether to render the footer
if ($isPartial === false) {
  // Get the footer include
  require_once($_SERVER['DOCUMENT_ROOT'] . '/includes/site-footer.php');

  // Render the footer
  siteFooter();
}
?>

ऊपर दिए गए उदाहरण में, कॉन्टेंट के पार्शियल को फ़ंक्शन के तौर पर शुरू किया गया है. इसमें, $isPartial की वैल्यू की मदद से, पार्शियल को रेंडर करने का तरीका बदला जा सकता है. उदाहरण के लिए, हो सकता है कि content रेंडरर फ़ंक्शन, कुछ स्थितियों में सिर्फ़ कुछ मार्कअप शामिल करे. ऐसा तब हो सकता है, जब उसे पार्शियल के तौर पर फिर से हासिल किया गया हो. कुछ ही समय में इसके बारे में जानकारी मिल जाएगी.

ज़रूरी बातें

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

नेविगेट करते समय पेज के एलिमेंट अपडेट करना

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

इससे बचने का तरीका यह है कि आप कुछ ज़रूरी चीज़ों को अपडेट करने के लिए, नेटवर्क से मिलने वाले कॉन्टेंट के कुछ हिस्से में इनलाइन <script> एलिमेंट जोड़ें:

<!-- The JSON below contains information about the current page. -->
<script id="page-data" type="application/json">'{"title":"Sand Wasp &mdash; World of Wasps","description":"Read all about the sand wasp in this tidy little post."}'</script>
<script>
  const pageData = JSON.parse(document.getElementById('page-data').textContent);

  // Update the page title
  document.title = pageData.title;
</script>
<article>
  <!-- Page content omitted... -->
</article>

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

धीमे नेटवर्क से निपटना

प्री-कैशे के मार्कअप का इस्तेमाल करके, रिस्पॉन्स को स्ट्रीम करने की एक कमी तब हो सकती है, जब इंटरनेट कनेक्शन धीमा हो. समस्या यह है कि प्रीकैश से हेडर मार्कअप तुरंत पहुंच जाएगा, लेकिन हेडर मार्कअप के शुरुआती पेंट के बाद नेटवर्क से आंशिक रूप से काम करने वाला कॉन्टेंट आने में कुछ समय लग सकता है.

इससे भ्रम की स्थिति बन सकती है. साथ ही, अगर नेटवर्क बहुत धीमे काम करते हैं, तो आपको ऐसा लग सकता है कि पेज काम नहीं कर रहा है और वह रेंडर नहीं हो रहा है. इस तरह के मामलों में, कॉन्टेंट को आंशिक तौर पर दिखाने वाले मार्कअप में लोड होने वाला आइकॉन या मैसेज दिखाया जा सकता है. इस डेटा को कॉन्टेंट लोड होने के बाद छिपाया जा सकता है.

ऐसा करने का एक तरीका सीएसएस का इस्तेमाल करना है. मान लें कि आपक�� हेडर का कुछ हिस्सा, ओपनिंग <article> एलिमेंट के साथ खत्म होता है. इसे तब तक खाली रखा जाता है, जब तक कॉन्टेंट का कुछ हिस्सा अपने-आप नहीं भर जाता. आप इसके जैसा एक सीएसएस नियम लिख सकते हैं:

article:empty::before {
  text-align: center;
  content: 'Loading...';
}

यह काम करता है, लेकिन नेटवर्क की रफ़्तार पर ध्यान दिए बिना, यह क्लाइंट पर लोड होने का मैसेज दिखाएगा. अगर आपको मैसेज भेजने के गलत तरीके से बचना है, तो यह तरीका आज़माएं. यहां हम ऊपर दिए गए स्निपेट में सिलेक्टर को slow क्लास में नेस्ट करते हैं:

.slow article:empty::before {
  text-align: center;
  content: 'Loading...';
}

यहां से आप चुनिंदा कनेक्शन टाइप पर <html> एलिमेंट में slow क्लास जोड़ने के लिए, असरदार कनेक्शन टाइप (कम से कम Chromium ब्राउज़र में) पढ़ने के लिए, अपने हेडर के पार्शियल में JavaScript का इस्तेमाल कर सकते हैं:

<script>
  const effectiveType = navigator?.connection?.effectiveType;

  if (effectiveType !== '4g') {
    document.documentElement.classList.add('slow');
  }
</script>

इससे यह पक्का होगा कि 4g टाइप से धीमे कनेक्शन टाइप को लोड होने का मैसेज मिलेगा. इसके बाद, लोड होने वाले मैसेज को हटाने के लिए, कॉन्टेंट के कुछ हिस्से में इनलाइन <script> एलिमेंट को रखा जा सकता है. इससे एचटीएमएल से slow क्लास को हटाया जा सकता है:

<script>
  document.documentElement.classList.remove('slow');
</script>

फ़ॉलबैक जवाब देना

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

फ़ॉलबैक रिस्पॉन्स पाने के लिए ज़रूरी कोड, पिछले कोड सैंपल में दिखाया गया है. इस प्रक्रिया के लिए दो चरणों की ज़रूरत होती है:

  1. ऑफ़लाइन फ़ॉलबैक रिस्पॉन्स को पहले से कैश मेमोरी में सेव करें.
  2. नेटवर्क-फ़र्स्ट स्ट्रेटजी के लिए प्लगिन में handlerDidError कॉलबैक सेट अप करें, ताकि पेज के आखिरी बार ऐक्सेस किए गए वर्शन की कैश मेमोरी की जांच की जा सके. अगर पेज कभी ऐक्सेस नहीं किया गया था, तो आपको प्री-कैश मेमोरी से फ़ॉलबैक रिस्पॉन्स पाने के लिए, workbox-precaching मॉड्यूल से matchPrecache तरीके का इस्तेमाल करना होगा.

कैश मेमोरी में सेव करना और सीडीएन

अगर सर्विस वर्कर में इस स्ट्रीमिंग पैटर्न का इस्तेमाल किया जा रहा है, तो देखें कि आपकी स्थिति पर ये बातें लागू होती हैं या नहीं:

  • आप सीडीएन या किसी दूसरे तरह के इंटरमीडिएट/सार्वजनिक कैश का इस्तेमाल करते हों.
  • आपने public डायरेक्टिव के साथ, एक ऐसा Cache-Control हेडर बताया है जिसमें शून्य नहीं max-age और/या s-maxage डायरेक्टिव शामिल हैं.

अगर आपके मामले में ये दोनों बातें लागू होती हैं, तो बीच में आने वाली कैश मेमोरी, नेविगेशन के अनुरोधों के लिए जवाबों को रोक सकती है. हालांकि, याद रखें कि जब इस पैटर्न का इस्तेमाल किया जाता है, तो हो सकता है कि आपने किसी यूआरएल के लिए दो अलग-अलग रिस्पॉन्स दिए हों:

  • पूरा जवाब, जिसमें हेडर, कॉन्टेंट, और फ़ुटर मार्कअप शामिल है.
  • अधूरे जवाब, जिसमें सिर्फ़ कॉन्टेंट शामिल है.

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

इस समस्या को हल करने के लिए, आपको Vary हेडर पर भरोसा करना होगा. इससे, अनुरोध में मौजूद एक या एक से ज़्यादा हेडर के लिए, कैश मेमोरी में सेव किए जा सकने वाले रिस्पॉन्स को कुंजी बनाकर, कैश मेमोरी में सेव किया जा सकता है. हम नेविगेशन के अनुरोधों के लिए, Service-Worker-Navigation-Preload और पसंद के मुताबिक बनाए गए X-Content-Mode अनुरोध हेडर के आधार पर अलग-अलग जवाब दे रहे हैं. इसलिए, हमें जवाब में यह Vary हेडर बताना होगा:

Vary: Service-Worker-Navigation-Preload,X-Content-Mode

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

नतीजा

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

तेज़ कॉन्टेंट के लिए फ़न हैक्स में जेक आर्चिबाल्ड

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

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

  • आम तौर पर, पहली बाइट का समय (टीटीएफ़बी) काफ़ी कम हो जाएगा, क्योंकि नेविगेशन के अनुरोध के जवाब का पहला बाइट तुरंत मिलता है.
  • फ़र्स्ट कॉन्टेंटफ़ुल पेंट (एफ़सीपी) बहुत तेज़ काम करेगा, क्योंकि पहले से कैश किए गए हेडर मार्कअप में कैश मेमोरी की स्टाइल शीट का रेफ़रंस शामिल होगा. इसका मतलब है कि पेज बहुत तेज़ी से पेंट करेगा.
  • कुछ मामलों में, सबसे बड़े एलिमेंट को रेंडर करने में लगने वाला समय (एलसीपी) भी ज़्यादा तेज़ हो सकता है. खास तौर पर तब, जब स्क्रीन पर सबसे बड़ा एलिमेंट पहले से कैश मेमोरी में सेव किए गए हेडर से मिला हो. फिर भी, छोटे मार्कअप पेलोड के साथ मिलकर जल्द से जल्द सर्विस वर्कर कैश से कुछ बाहर करने से बेहतर एलसीपी मिल सकता है.

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

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

संसाधन