JavaScript के साथ इंटरैक्टिविटी जोड़ना

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

खास जानकारी

  • JavaScript, DOM और CSSOM पर क्वेरी कर सकता है और उसमें बदलाव कर सकता है.
  • CSSOM पर JavaScript निष्पादन ब्लॉक.
  • JavaScript, डीओएम बनाने से रोकता है. ऐसा तब तक होता है, जब तक कि उसे एक साथ काम नहीं करने वाली प्रोसेस के तौर पर बताया गया हो.

JavaScript एक डाइनैमिक भाषा है, जो किसी ब्राउज़र में चलती है. इसकी मदद से हम पेज के हर पहलू में बदलाव कर सकते हैं: हम डीओएम ट्री में एलिमेंट जोड़कर या हटाकर कॉन्टेंट में बदलाव कर सकते हैं, हर एलिमेंट की CSSOM प्रॉपर्टी में बदलाव कर सकते हैं, उपयोगकर्ता के इनपुट के साथ-साथ और भी बहुत कुछ कर सकते हैं. इसे समझने के लिए, आइए अपने पिछले "Hello World" वाले उदाहरण को एक आसान इनलाइन स्क्रिप्ट की मदद से बेहतर बनाते हैं:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline'; // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var loadTime = document.createElement('div');
      loadTime.textContent = 'You loaded this page on: ' + new Date();
      loadTime.style.color = 'blue';
      document.body.appendChild(loadTime);
    </script>
  </body>
</html>

इसे आज़माएँ

  • JavaScript की मदद से, हम डीओएम तक पहुंच करके छिपे हुए स्पैन नोड का रेफ़रंस ले सकते हैं. ऐसा हो सकता है कि रेंडर ट्री में नोड न दिखे, लेकिन डीओएम में वह अब भी मौजूद हो. इसके बाद, जब हमारे पास रेफ़रंस होता है, तो हम .textContent की मदद से उसके टेक्स्ट को बदल सकते हैं. साथ ही, इसकी कैलकुलेट की गई डिसप्ले स्टाइल प्रॉपर्टी को "कोई नहीं" से "इनलाइन" में बदल सकते हैं. अब हमारे पेज पर "नमस्ते, इंटरैक्टिव छात्र/छात्रा!" का विकल्प दिखता है.

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

पेज की झलक

इसे ध्यान में रखते हुए, हमने किसी मौजूदा डीओएम नोड के कॉन्टेंट और सीएसएस स्टाइल में बदलाव किया है. साथ ही, दस्तावेज़ में पूरी तरह से नया नोड जोड़ा है. हमारा पेज डिज़ाइन के लिए कोई इनाम नहीं जीतेगा, लेकिन यह JavaScript की ताकत और सुविधा को दिखाता है.

हालांकि, JavaScript में हमें काफ़ी क्षमता मिलती है, लेकिन यह पेज को रेंडर करने के तरीके और समय पर कई अन्य सीमाएं लागू करता है.

सबसे पहले, ध्यान दें कि ऊपर दिए गए उदाहरण में हमारी इनलाइन स्क्रिप्ट, पेज पर सबसे नीचे मौजूद है. ऐसा क्यों हो रहा है? ठीक है, आपको इसे खुद आज़माकर देखना चाहिए, लेकिन अगर हम स्क्रिप्ट को span एलिमेंट से ऊपर ले जाते हैं, तो स्क्रिप्ट काम नहीं करती और शिकायत करेगी कि उसे दस्तावेज़ में किसी span एलिमेंट का रेफ़रंस नहीं मिल रहा है; यानी, getElementsByTagName(‘span') null दिखाता है. यह एक अहम प्रॉपर्टी को दिखाता है: हमारी स्क्रिप्ट उसी पॉइंट पर काम करती है जहां उसे दस्तावेज़ में डाला गया था. जब एचटीएमएल पार्सर को कोई स्क्रिप्ट टैग मिलता है, तो वह डीओएम बनाने की प्रोसेस को रोक देता है और JavaScript इंजन को कंट्रोल देता है. JavaScript इंजन के चलने का काम पूरा होने के बाद, ब्राउज़र वहीं से शुरू करता है जहां उसे छोड़ा गया था और डीओएम बनाना फिर से शुरू कर देता है.

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

हमारे पेज पर स्क्रिप्ट को पेश करने की एक और बेहतरीन खासियत यह है कि वे न सिर्फ़ डीओएम को, बल्कि CSSOM प्रॉपर्टी को भी पढ़ सकते हैं और उनमें बदलाव कर सकते हैं. असल में, हम अपने उदाहरण में ऐसा ही कर रहे हैं. ऐसा तब करते हैं, जब हम span एलिमेंट की डिसप्ले प्रॉपर्टी को'कोई नहीं' से इनलाइन में बदलते हैं. अंतिम नतीजा? अब हमारे पास रेस कंडिशन है.

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

कम शब्दों में कहें, तो JavaScript से DOM, CSSOM, और JavaScript एक्ज़ीक्यूशन के बीच कई नई डिपेंडेंसी मिलती हैं. इससे, ब्राउज़र को स्क्रीन पर पेज को प्रोसेस और रेंडर करने में ज़्यादा समय लग सकता है:

  • दस्तावेज़ में स्क्रिप्ट की जगह अहम है.
  • जब ब्राउज़र को कोई स्क्रिप्ट टैग मिलता है, तो डीओएम कंस्ट्रक्शन तब तक रुक जाता है, जब तक स्क्रिप्ट पूरी तरह लागू नहीं हो जाती.
  • JavaScript, DOM और CSSOM पर क्वेरी कर सकता है और उसमें बदलाव कर सकता है.
  • CSSOM तैयार होने तक JavaScript एक्ज़ीक्यूशन रुक जाता है.

एक हद तक, "क्रिटिकल रेंडरिंग पाथ को ऑप्टिमाइज़ करने" का मतलब है, एचटीएमएल, सीएसएस, और JavaScript के बीच डिपेंडेंसी ग्राफ़ को समझना और उसे ऑप्टिमाइज़ करना.

पार्सर ब्लॉकिंग बनाम एसिंक्रोनस JavaScript

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

स्क्रिप्ट टैग में शामिल की गई स्क्रिप्ट का क्या होगा? आइए हमारे पिछले उदाहरण पर जाएं और कोड को एक अलग फ़ाइल में एक्सट्रैक्ट करें:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script External</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script src="app.js"></script>
  </body>
</html>

app.js

var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);

इसे आज़माएँ

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

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

इसके लिए, हम अपनी स्क्रिप्ट को async के तौर पर मार्क करते हैं:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script Async</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script src="app.js" async></script>
  </body>
</html>

इसे आज़माएँ

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

सुझाव/राय दें या शिकायत करें