तीसरे पक्ष का JavaScript ऑप्टिमाइज़ करना

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

  • स्क्रिप्ट लोड होने में लगने वाले समय को कम करना

  • अहम नहीं होने वाले रिसॉर्स को लेज़ी लोड करना

  • ज़रूरी ऑरिजिन से पहले से कनेक्ट करना

सैंपल ऐप्लिकेशन में एक आसान वेब पेज है. इसमें तीसरे पक्ष के सोर्स से मिलने वाली तीन सुविधाएं हैं:

  • एम्बेड किया गया वीडियो

  • लाइन ग्राफ़ को रेंडर करने के लिए डेटा-विज़ुअलाइज़ेशन लाइब्रेरी

  • सोशल मीडिया पर शेयर करने वाला विजेट

तीसरे पक्ष के संसाधनों को हाइलाइट किए गए पेज का स्क्रीनशॉट.
सैंपल ऐप्लिकेशन में तीसरे पक्ष के संसाधन.

आपको सबसे पहले ऐप्लिकेशन की परफ़ॉर्मेंस का आकलन करना होगा. इसके बाद, हर तकनीक का इस्तेमाल करके, ऐप्लिकेशन की परफ़ॉर्मेंस के अलग-अलग पहलुओं को बेहतर करना होगा.

परफ़ॉर्मेंस का आकलन करना

सबसे पहले, सैंपल ऐप्लिकेशन को फ़ुल स्क्रीन व्यू में खोलें:

  1. प्रोजेक्ट में बदलाव करने के लिए, बदलाव करने के लिए रीमिक्स करें पर क्लिक करें.
  2. साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीनफ़ुलस्क्रीन दबाएं.

पेज की परफ़ॉर्मेंस का बेसलाइन तय करने के लिए, उस पर Lighthouse परफ़ॉर्मेंस ऑडिट चलाएं:

  1. DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं.
  2. Lighthouse टैब पर क्लिक करें.
  3. मोबाइल पर क्लिक करें.
  4. परफ़ॉर्मेंस चेकबॉक्स चुनें. (ऑडिट सेक्शन में जाकर, बाकी चेकबॉक्स हटाए जा सकते हैं.)
  5. सिम्युलेटेड फ़ास्ट 3G, 4x सीपीयू स्लोडाउन पर क्लिक करें.
  6. स्टोरेज खाली करें चेकबॉक्स चुनें.
  7. ऑडिट चलाएं पर क्लिक करें.

अपनी मशीन पर ऑडिट करने पर, सटीक नतीजे अलग-अलग हो सकते हैं. हालांकि, आपको यह पता चलना चाहिए कि साइट का पहला एलिमेंट लोड होने में लगने वाला समय (एफ़सीपी) काफ़ी ज़्यादा है. साथ ही, Lighthouse ने जांच के लिए दो सुझाव दिए हैं: रेंडर करने से रोकने वाले संसाधनों को हटाएं और ज़रूरी ऑरिजिन से पहले कनेक्ट करें. (भले ही, सभी मेट्रिक हरे रंग में हों, फिर भी ऑप्टिमाइज़ेशन से सुधार होगा.)

Lighthouse ऑडिट का स्क्रीनशॉट, जिसमें 2.4 सेकंड का एफ़सीपी और दो अवसर दिख रहे हैं: रेंडर ब्लॉक करने वाले संसाधनों को हटाएं और ज़रूरी ऑरिजिन से पहले से कनेक्ट करें.

तीसरे पक्ष की JavaScript को बाद में लोड करना

रेंडर ब्लॉक करने वाले रिसॉर्स हटाएं ऑडिट से पता चला है कि d3js.org से आने वाली स्क्रिप्ट को कुछ समय के लिए रोककर, कुछ समय बचाया जा सकता है:

रेंडर ब्लॉक करने वाले संसाधनों को हटाने से जुड़े ऑडिट का स्क्रीनशॉट, जिसमें d3.v3.min.js स्क्रिप्ट को हाइलाइट किया गया है.

D3.js, डेटा विज़ुअलाइज़ेशन बनाने के लिए JavaScript लाइब्रेरी है. सैंपल ऐप्लिकेशन में मौजूद script.js फ़ाइल, SVG लाइन चार्ट बनाने और उसे पेज में जोड़ने के लिए, D3 यूटिलिटी फ़ंक्शन का इस्तेमाल करती है. यहां क्रम का ध्यान रखना ज़रूरी है: दस्तावेज़ को पार्स करने और D3 लाइब्रेरी लोड होने के बाद, script.js को चलाना होगा. इसलिए, इसे index.html में क्लोज़िंग </body> टैग से ठीक पहले शामिल किया गया है.

हालांकि, D3 स्क्रिप्ट को पेज के <head> में शामिल किया गया है, जो बाकी दस्तावेज़ को पार्स करने से रोकती है:

index.html का स्क्रीनशॉट, जिसमें हेडर में हाइलाइट किया गया स्क्रिप्ट टैग है.

स्क्रिप्ट टैग में दो मैजिक एट्रिब्यूट जोड़ने पर, पार्सर को अनब्लॉक किया जा सकता है:

  • async यह पक्का करता है कि स्क्रिप्ट बैकग्राउंड में डाउनलोड हो जाएं और डाउनलोड पूरा होने के बाद, पहली बार लागू हो जाएं.

  • defer यह पक्का करता है कि स्क्रिप्ट बैकग्राउंड में डाउनलोड हो जाएं और पार्स करने के बाद, स्क्रिप्ट एक्ज़ीक्यूट हो जाए.

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

पहला चरण: defer एट्रिब्यूट के साथ, स्क्रिप्ट को असिंक्रोनस तरीके से लोड करना

index.html की लाइन 17 पर, <script> एलिमेंट में defer एट्रिब्यूट जोड़ें:

<script src="https://d3js.org/d3.v3.min.js" defer></script>

दूसरा चरण: पक्का करना कि ऑपरेशन का क्रम सही हो

D3 को बाद में चलाने के बाद, script.js D3 के तैयार होने से पहले चलेगा. इस वजह से, गड़बड़ी होगी.

defer एट्रिब्यूट वाली स्क्रिप्ट उसी क्रम में लागू होती हैं जिस क्रम में उन्हें तय किया गया था. D3 के तैयार होने के बाद script.js को लागू करने के लिए, उसमें defer जोड़ें और उसे दस्तावेज़ के <head> में ले जाएं. यह D3 <script> एलिमेंट के ठीक बाद होना चाहिए. अब यह पार्स करने वाले टूल को ब्लॉक नहीं करता और डाउनलोड जल्दी शुरू हो जाता है.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

तीसरे पक्ष के संसाधनों को लेज़ी लोड करना

फ़ोल्ड के नीचे मौजूद सभी संसाधन, लेज़ी लोडिंग के लिए अच्छे विकल्प हैं.

सैंपल ऐप्लिकेशन में, iframe में एम्बेड किया गया YouTube वीडियो है. यह देखने के लिए कि पेज कितने अनुरोध करता है और वे एम्बेड किए गए YouTube iframe से आते हैं या नहीं:

  1. साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीनफ़ुलस्क्रीन दबाएं.
  2. DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं.
  3. नेटवर्क टैब पर क्लिक करें.
  4. कैश मेमोरी की सुविधा बंद करें चेकबॉक्स को चुनें.
  5. थ्रॉटल करने की सुविधा ड्रॉपडाउन मेन्यू में, फास्ट 3G चुनें.
  6. पेज को फिर से लोड करें.

DevTools के नेटवर्क पैनल का स्क्रीनशॉट.

नेटवर्क पैनल से पता चलता है कि इस पेज ने कुल 28 अनुरोध किए और करीब एक एमबी कंप्रेस किए गए संसाधन ट्रांसफ़र किए.

YouTube iframe के अनुरोधों की पहचान करने के लिए, इनीशियेटर कॉलम में वीडियो आईडी 6lfaiXM6waw देखें. सभी अनुरोधों को डोमेन के हिसाब से ग्रुप करने के लिए:

  • नेटवर्क पैनल में, किसी कॉलम के शीर्षक पर राइट क्लिक करें.

  • ड्रॉपडाउन मेन्यू में, डोमेन कॉलम चुनें.

  • अनुरोधों को डोमेन के हिसाब से क्रम से लगाने के लिए, डोमेन कॉलम के टाइटल पर क्लिक करें.

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

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

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

पहला चरण: वीडियो को शुरू में लोड होने से रोकना

वीडियो iframe को लेज़ी-लोड करने के लिए, आपको पहले उसे सामान्य तरीके से लोड होने से रोकना होगा. ऐसा करने के लिए, src एट्रिब्यूट को data-src एट्रिब्यूट से बदलें, ताकि वीडियो के यूआरएल की जानकारी दी जा सके:

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src एक डेटा एट्रिब्यूट है. इसकी मदद से, स्टैंडर्ड एचटीएमएल एलिमेंट में ज़्यादा जानकारी सेव की जा सकती है. डेटा एट्रिब्यूट का नाम कुछ भी हो सकता है. हालांकि, यह ज़रूरी है कि उसका नाम "data-" से शुरू हो.

बिना src वाला iframe लोड नहीं होता.

दूसरा चरण: वीडियो को धीरे-धीरे लोड करने के लिए, इंटरसेक्शन ऑब्ज़र्वर का इस्तेमाल करना

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

शुरू करने के लिए, एक नई फ़ाइल बनाएं और उसका नाम lazy-load.js रखें:

  • नई फ़ाइल पर क्लिक करें और उसे कोई नाम दें.
  • यह फ़ाइल जोड़ें पर क्लिक करें.

अपने दस्तावेज़ के हेड में स्क्रिप्ट टैग जोड़ें:

 <script src="/lazy-load.js" defer></script>

lazy-load.js में, नया IntersectionObserver बनाएं और उसे चलाने के लिए कॉलबैक फ़ंक्शन पास करें:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

अब observer को देखने के लिए कोई टारगेट एलिमेंट दें (इस मामले में वीडियो iframe). इसके लिए, observe तरीके में इसे आर्ग्युमेंट के तौर पर पास करें:

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callback को IntersectionObserverEntry ऑब्जेक्ट की सूची और IntersectionObserver ऑब्जेक्ट मिलता है. हर एंट्री में एक target एलिमेंट और प्रॉपर्टी होती हैं. इनसे, एलिमेंट के डाइमेंशन, पोज़िशन, व्यूपोर्ट में दिखने का समय वगैरह के बारे में पता चलता है. IntersectionObserverEntry की एक प्रॉपर्टी isIntersecting है. यह एक बूलियन वैल्यू है, जो एलिमेंट के व्यूपोर्ट में शामिल होने पर true के बराबर होती है.

इस उदाहरण में, target, iframe है. target के व्यूपोर्ट में शामिल होने पर, isIntersecting true के बराबर होता है. इसे काम करने के लिए देखने के लिए, callback को नीचे दिए गए फ़ंक्शन से बदलें:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीनफ़ुलस्क्रीन दबाएं.
  2. DevTools खोलने के लिए, `Control+Shift+J` दबाएं. Mac पर, `Command+Option+J` दबाएं.
  3. कंसोल टैब पर क्लिक करें.

ऊपर और नीचे स्क्रोल करके देखें. आपको isIntersecting बदलाव की वैल्यू और कंसोल में लॉग किए गए टारगेट एलिमेंट दिखेंगे.

जब उपयोगकर्ता वीडियो पर स्क्रोल करके उसकी पोज़िशन पर पहुंचता है, तब वीडियो लोड करने के लिए, loadElement फ़ंक्शन को चलाने के लिए isIntersecting का इस्तेमाल करें. यह फ़ंक्शन, iframe एलिमेंट के data-src से वैल्यू पाता है और उसे iframe एलिमेंट के src एट्रिब्यूट के तौर पर सेट करता है. इस बदलाव से, वीडियो लोड होना शुरू हो जाता है. इसके बाद, वीडियो लोड होने के बाद, टारगेट एलिमेंट को देखना बंद करने के लिए, observer पर unobserve तरीका लागू करें:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

तीसरा चरण: परफ़ॉर्मेंस का फिर से आकलन करना

रिसॉर्स का साइज़ और संख्या में हुए बदलावों को देखने के लिए, DevTools का नेटवर्क पैनल खोलें और पेज को फिर से लोड करें. नेटवर्क पैनल से पता चलता है कि पेज ने 14 अनुरोध किए और सिर्फ़ 260 केबी का डेटा ट्रांसफ़र किया. यह काफ़ी अच्छा सुधार है!

अब पेज पर नीचे की ओर स्क्रोल करें और नेटवर्क पैनल पर नज़र रखें. वीडियो पर पहुंचने के बाद, आपको पेज पर कुछ और अनुरोध दिखेंगे.

ज़रूरी ऑरिजिन के साथ पहले से कनेक्शन बनाना

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

किसी लिंक में rel=preconnect एट्रिब्यूट जोड़ने से, ब्राउज़र को उस संसाधन का अनुरोध करने से पहले, डोमेन से कनेक्शन बनाने के लिए कहा जाता है. इस एट्रिब्यूट का इस्तेमाल उन ऑरिजिन के लिए सबसे अच्छा होता है जो ऐसे रिसॉर्स उपलब्ध कराते हैं जिनकी ज़रूरत पेज को है.

ज़रूरी ऑरिजिन के साथ पहले से कनेक्शन बनाने के पहले चरण में चलाए गए Lighthouse ऑडिट से पता चला है कि staticxx.facebook.com और youtube.com से पहले से कनेक्शन बनाकर, करीब 400 मिलीसेकंड बचाए जा सकते हैं:

ज़रूरी ऑरिजिन ऑडिट से पहले से कनेक्ट करें, जिसमें staticxx.facebook.com डोमेन हाइलाइट किया गया हो.

YouTube वीडियो अब लेज़ी-लोड होता है. इसलिए, सिर्फ़ staticxx.facebook.com ही सोशल मीडिया शेयरिंग विजेट का सोर्स है. इस डोमेन से पहले से कनेक्ट करना उतना ही आसान है जितना कि दस्तावेज़ के <head> में <link> टैग जोड़ना:

  <link rel="preconnect" href="https://staticxx.facebook.com">

परफ़ॉर्मेंस का फिर से आकलन करना

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

लाइटहाउस ऑडिट, जिसमें एफ़सीपी एक सेकंड और परफ़ॉर्मेंस स्कोर 99 है.