पब्लिश करने की तारीख: 31 दिसंबर, 2013
JavaScript की मदद से, पेज के हर पहलू में बदलाव किया जा सकता है: कॉन्टेंट, स्टाइल, और उपयोगकर्ता के इंटरैक्शन के जवाब में. हालांकि, JavaScript, डीओएम के बनने को भी रोक सकता है और पेज के रेंडर होने में देरी कर सकता है. बेहतर परफ़ॉर्मेंस देने के लिए, अपने JavaScript को एसिंक्रोनस बनाएं और रेंडरिंग के अहम पाथ से ग़ैर-ज़रूरी JavaScript को हटाएं.
खास जानकारी
- JavaScript, डीओएम और सीएसएसओएम से क्वेरी कर सकता है और उनमें बदलाव कर सकता है.
- CSSOM पर JavaScript को चलाने से जुड़ी समस्याएं.
- JavaScript, DOM के निर्माण को तब तक ब्लॉक करता है, जब तक कि साफ़ तौर पर एस्किन के तौर पर एलान न किया जाए.
JavaScript एक डाइनैमिक भाषा है, जो ब्राउज़र में चलती है. इसकी मदद से, पेज के काम करने के तरीके के हर पहलू में बदलाव किया जा सकता है: हम डीओएम ट्री में एलिमेंट जोड़कर और हटाकर कॉन्टेंट में बदलाव कर सकते हैं. साथ ही, हम हर एलिमेंट की सीएसएसओएम प्रॉपर्टी में बदलाव कर सकते हैं. इसके अलावा, हम उपयोगकर्ता के इनपुट को मैनेज कर सकते हैं और बहुत कुछ कर सकते हैं. इसे दिखाने के लिए, देखें कि छोटी इनलाइन स्क्रिप्ट जोड़ने के लिए, पिछले "Hey 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 की मदद से, डीओएम में नए एलिमेंट बनाए जा सकते हैं, उनकी स्टाइल तय की जा सकती है, उन्हें जोड़ा जा सकता है, और हटाया जा सकता है. तकनीकी रूप से, हमारा पूरा पेज सिर्फ़ एक बड़ी JavaScript फ़ाइल हो सकती है, जो एलिमेंट को एक-एक करके बनाती और स्टाइल करती है. वैसे तो यह काम करेगा, लेकिन असल में एचटीएमएल और सीएसएस का इस्तेमाल करना ज़्यादा आसान है. अपने JavaScript फ़ंक्शन के दूसरे हिस्से में, हम एक नया div एलिमेंट बनाते हैं, उसका टेक्स्ट कॉन्टेंट सेट करते हैं, उसे स्टाइल देते हैं, और उसे बॉडी में जोड़ते हैं.
इसके बाद, हमने मौजूदा DOM नोड के कॉन्टेंट और सीएसएस स्टाइल में बदलाव किया है. साथ ही, दस्तावेज़ में एक नया नोड जोड़ा है. हमारा पेज, डिज़ाइन के लिए कोई पुरस्कार नहीं जीतेगा. हालांकि, इससे पता चलता है कि JavaScript हमें कितनी सुविधाएं और बेहतरीन परफ़ॉर्मेंस देता है.
हालांकि, JavaScript हमें कई सुविधाएं देता है, लेकिन इससे पेज को रेंडर करने के तरीके और समय पर कई और सीमाएं आती हैं.
सबसे पहले, ध्यान दें कि पिछले उदाहरण में हमारी इनलाइन स्क्रिप्ट, पेज के सबसे नीचे है. क्यों? आपको खुद ही इसे आज़माना चाहिए. हालांकि, अगर हम स्क्रिप्ट को <span>
एलिमेंट के ऊपर ले जाते हैं, तो आपको पता चलेगा कि स्क्रिप्ट काम नहीं करती और यह शिकायत करती है कि उसे दस्तावेज़ में किसी भी <span>
एलिमेंट का रेफ़रंस नहीं मिला है. इसका मतलब है कि getElementsByTagName('span')
, null
दिखाता है. इससे एक अहम प्रॉपर्टी के बारे में पता चलता है: हमारी स्क्रिप्ट ठीक उसी समय एक्ज़ीक्यूट होती है जहां उसे दस्तावेज़ में डाला गया होता है. जब एचटीएमएल पार्स करने वाला टूल किसी स्क्रिप्ट टैग को पाता है, तो वह डीओएम बनाने की प्रोसेस को रोक देता है और JavaScript इंजन को कंट्रोल दे देता है. JavaScript इंजन के बंद होने के बाद, ब्राउज़र उस जगह से फिर से शुरू होता है जहां से वह रुका था और डीओएम बनाना फिर से शुरू करता है.
दूसरे शब्दों में, हमारे स्क्रिप्ट ब्लॉक को पेज में बाद में कोई एलिमेंट नहीं मिल सकता, क्योंकि उन्हें अभी तक प्रोसेस नहीं किया गया है! या इसे थोड़ा अलग तरीके से रखें: हमारी इनलाइन स्क्रिप्ट चलाने से डीओएम कंस्ट्रक्शन ब्लॉक हो जाता है. इससे शुरुआती रेंडर में भी देरी होती है.
हमारे पेज में स्क्रिप्ट जोड़ने की एक और खास बात यह है कि वे न सिर्फ़ DOM, बल्कि CSSOM प्रॉपर्टी को भी पढ़ सकती हैं और उनमें बदलाव कर सकती हैं. असल में, हम अपने उदाहरण में यही कर रहे हैं. इसके लिए, हमने स्पैन एलिमेंट की डिसप्ले प्रॉपर्टी को 'कोई नहीं' से 'इनलाइन' में बदला है. आखिर में क्या होगा? अब हमारी रेस कंडीशन है.
अगर हमें अपनी स्क्रिप्ट चलाने के लिए, ब्राउज़र में CSSOM बनाना होगा, तो क्या होगा? परफ़ॉर्मेंस के लिहाज़ से, यह जवाब बहुत अच्छा नहीं है: ब्राउज़र, CSSOM को डाउनलोड और बनाकर तैयार करने तक, स्क्रिप्ट को चलाने और DOM बनाने में देरी करता है.
कम शब्दों में, JavaScript, डीओएम, सीएसएसओएम, और 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 फ़ाइल के मामले में, ब्राउज़र को डिस्क, कैश मेमोरी या किसी रिमोट सर्वर से स्क्रिप्ट फ़ेच होने का इंतज़ार करने के लिए रोकना पड़ता है. इससे, क्रिटिकल रेंडरिंग पाथ में 10 से 1,000 मिलीसेकंड की देरी हो सकती है.
डिफ़ॉल्ट रूप से, सभी JavaScript को पार्स करने से रोका जाता है. ब्राउज़र को नहीं पता कि स्क्रिप्ट, पेज पर क्या करने वाली है. इसलिए, वह सबसे खराब स्थिति को मानकर पार्सर को ब्लॉक कर देता है. इससे ब्राउज़र को यह पता चलता है कि स्क्रिप्ट को उसी जगह पर एक्ज़ीक्यूट करना ज़रूरी नहीं है जहां उसका रेफ़रंस दिया गया है. इससे ब्राउज़र, डीओएम को बनाना जारी रख सकता है और स्क्रिप्ट तैयार होने पर उसे एक्ज़ीक्यूट करने देता है. उदाहरण के लिए, कैश मेमोरी या रिमोट सर्वर से फ़ाइल फ़ेच किए जाने के बाद.
ऐसा करने के लिए, async
एट्रिब्यूट को <script>
एलिमेंट में जोड़ा जाता है:
<!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>
स्क्रिप्ट टैग में एसिंक कीवर्ड जोड़ने से, ब्राउज़र को DOM निर्माण को ब्लॉक नहीं करने का निर्देश मिलता है, जब वह स्क्रिप्ट उपलब्ध होने का इंतज़ार करता है, जिससे प्रदर्शन में काफ़ी सुधार हो सकता है.