स्क्रिप्ट लोड होने के दौरान, गंदे पानी में डूबी रहें

शुरुआती जानकारी

इस लेख में, मैं आपको ब्राउज़र में JavaScript लोड करने और उसे इस्तेमाल करने के तरीके के बारे में बताऊंगा.

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

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

स्क्रिप्ट लोड होने पर WHATWG
स्क्रिप्ट लोड होने पर WHATWG

whatWG की सभी खास बातों की तरह, शुरुआत में यह किसी स्क्रैबल फ़ैक्ट्री में लगे क्लस्टर बम के बाद जैसा दिखता है, लेकिन अगर आपने इसे पांचवीं बार पढ़कर अपनी आंखों से खून को साफ़ कर दिया, तो असल में यह काफ़ी दिलचस्प है:

मेरी पहली स्क्रिप्ट में शामिल है

<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>

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

दुर्भाग्य से, यह सब होने के दौरान ब्राउज़र पेज की और रेंडरिंग रोक देता है. ऐसा "वेब की पहली उम्र" के डीओएम एपीआई की वजह से होता है. इसकी मदद से, पार्सर के कॉन्टेंट में स्ट्रिंग जोड़ने की अनुमति मिलती है, जैसे कि document.write. नए ब्राउज़र, बैकग्राउंड में चल रहे दस्तावेज़ को स्कैन या पार्स करते रहेंगे. साथ ही, बाहरी कॉन्टेंट (js, इमेज, सीएसएस वगैरह) के लिए डाउनलोड ट्रिगर करेंगे. हालांकि, रेंडरिंग अब भी ब्लॉक है.

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

धन्यवाद IE! (नहीं, मैं व्यंग्य नहीं कर रहा हूं)

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Microsoft ने परफ़ॉर्मेंस की इन समस्याओं को पहचाना और Internet Explorer 4 में "डिफ़ॉल्ट" को शामिल कर लिया. इसका मतलब है, “मैं वादा करता/करती हूं कि document.write जैसी चीज़ों का इस्तेमाल करके पार्सर में प्रॉडक्ट नहीं डाले जाएंगे. अगर मैं उस वादे को तोड़ दूं, तो आप मुझे किसी भी तरह से सही सज़ा देने के लिए स्वतंत्र हैं”. इस एट्रिब्यूट ने इसे HTML4 में बनाया था और दूसरे ब्राउज़र में भी देखा गया था.

ऊपर दिए गए उदाहरण में, ब्राउज़र साथ-साथ दोनों स्क्रिप्ट डाउनलोड करेगा और DOMContentLoaded के फ़ायर होने से ठीक पहले उन्हें लागू करेगा. इससे उनके क्रम में कोई बदलाव नहीं होगा.

भेड़ की फ़ैक्ट्री में हुए क्लस्टर-बम की तरह, “डिफ़र” भी ऊनी गंदगी बन गया. “src” और “defer” एट्रिब्यूट और स्क्रिप्ट टैग बनाम डाइनैमिक तौर पर जोड़ी गई स्क्रिप्ट के बीच, हमारे पास स्क्रिप्ट जोड़ने के छह पैटर्न हैं. बेशक, ब्राउज़र उस क्रम पर सहमत नहीं थे जिस क्रम में उन्हें काम करना चाहिए. Mozilla ने इस समस्या पर एक बेहतरीन टिप्पणी की क्योंकि 2009 में यह समस्या फिर से सामने आई.

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

धन्यवाद IE! (ठीक है, अब मैं व्यंग्य कर रहा हूं)

यह कुछ देता है, कुछ ले लेता है. माफ़ करें, IE4-9 में एक ऐसा गड़बड़ी मौजूद है जिसकी वजह से स्क्रिप्ट गलत क्रम में लागू हो सकती हैं. यहां बताया गया है कि क्या होता है:

1.js

console.log('1');
document.getElementsByTagName('p')[0].innerHTML = 'Changing some content';
console.log('2');

2.js

console.log('3');

यह मानते हुए कि पेज पर एक पैराग्राफ़ है, लॉग का अनुमानित क्रम [1, 2, 3] है, हालांकि, IE9 और उससे कम में आपको [1, 3, 2] मिलता है. कुछ खास डीओएम ऑपरेशन की वजह से IE मौजूदा स्क्रिप्ट के एक्ज़ीक्यूशन को रोक देता है और जारी रखने से पहले, बाकी बाकी स्क्रिप्ट को एक्ज़ीक्यूट कर देता है.

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

बचाव के लिए HTML5

<script src="//other-domain.com/1.js" async></script>
<script src="2.js" async></script>

HTML5 ने हमें “एक साथ काम नहीं करने वाली प्रोसेस” नाम का एक नया एट्रिब्यूट दिया है. यह मान लेता है कि आपको document.write का इस्तेमाल नहीं करना है. हालांकि, यह तब तक इंतज़ार नहीं करता, जब तक दस्तावेज़ पार्स नहीं हो जाता. ब्राउज़र साथ-साथ दोनों स्क्रिप्ट डाउनलोड करेगा और उन्हें जल्द से जल्द लागू करेगा.

माफ़ करें, वे जल्द से जल्द चलने वाले हैं, इसलिए “2.js” “1.js” से पहले काम कर सकते हैं. अगर वे स्वतंत्र हैं, तो शायद “1.js” एक ट्रैकिंग स्क्रिप्ट है, जिसका “2.js” से कोई लेना-देना नहीं है. हालांकि, अगर आपका “1.js” jQuery की एक CDN कॉपी है, जो कि “2.js” पर निर्भर करता है, तो आपका पेज इस क्लस्टर में आसानी से दिखेगा...

मुझे पता है कि हमें क्या चाहिए, एक JavaScript लाइब्रेरी!

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

JavaScript की मदद से इस समस्या को कुछ ही फ़्लेवर में हल किया गया था. कुछ मामलों में, JavaScript को सही क्रम में कॉल किए जाने वाले कॉलबैक में रैप करते हुए, आपको अपनी JavaScript में बदलाव करने होंगे. उदाहरण के लिए, RequireJS. दूसरे लोग, फ़ाइल को eval() के साथ सही क्रम में डाउनलोड करने के लिए, XHR का इस्तेमाल करेंगे. यह तरीका, किसी दूसरे डोमेन पर स्क्रिप्ट के लिए तब तक काम नहीं करता, जब तक कि उनके पास सीओआरएस हेडर न हो और ब्राउज़र उनके साथ काम करता हो. कुछ लोगों ने LabJS जैसे सुपर-मैजिक हैक का भी इस्तेमाल किया.

इसमें, ब्राउज़र को चकमा देकर संसाधन को इस तरह डाउनलोड किया जाता था जिससे इवेंट पूरा होने पर ट्रिगर हो जाए, लेकिन उसे एक्ज़ीक्यूट न करना. LabJS में, स्क्रिप्ट को गलत माइम प्रकार के साथ जोड़ दिया जाएगा, जैसे <script type="script/cache" src="...">. एक बार सभी स्क्रिप्ट डाउनलोड हो जाने के बाद, उन्हें सही प्रकार के साथ फिर से जोड़ दिया जाएगा, उम्मीद है कि ब्राउज़र उन्हें सीधे कैश से मिलेगा और उन्हें तुरंत लागू कर देगा. यह आसान, लेकिन अनजान व्यवहार पर निर्भर करता है. यह उस समय काम नहीं करता है, जब HTML5 के एलान किए गए ब्राउज़र को अनजान टाइप की स्क्रिप्ट डाउनलोड नहीं करनी चाहिए. ध्यान दें कि LabJS ने इन बदलावों को अपनाया है. अब इस लेख में दिए गए अलग-अलग तरीकों का इस्तेमाल किया जाता है.

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

दरअसल, अगर आपको कोई दूसरी स्क्रिप्ट डाउनलोड करने से पहले ही कोई और स्क्रिप्ट फ़ाइल डाउनलोड करनी पड़ती है, तो इसका मतलब है कि आपके कैंपेन की परफ़ॉर्मेंस खराब हो गई है.

बचाव के लिए डीओएम

असल में, इसका जवाब HTML5 स्पेसिफ़िकेशन में है. हालांकि, यह स्क्रिप्ट-लोडिंग सेक्शन के सबसे नीचे छिपा होता है.

चलिए, इसे “पृथ्वी” में बदलते हैं:

[
  '//other-domain.com/1.js',
  '2.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  document.head.appendChild(script);
});

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

[
  '//other-domain.com/1.js',
  '2.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

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

ऊपर दी गई स्क्रिप्ट को पेज के सबसे ऊपर इनलाइन तरीके से शामिल किया जाना चाहिए. साथ ही, लगातार होने वाली रेंडरिंग में रुकावट डाले बिना, स्क्रिप्ट डाउनलोड की सूची तैयार करनी चाहिए और जितनी जल्दी हो सके, आपके तय किए क्रम में काम करना चाहिए. “2.js” को “1.js” से पहले मुफ़्त में डाउनलोड किया जा सकता है. हालांकि, इसे तब तक डाउनलोड नहीं किया जा सकता, जब तक कि “1.js” पूरी तरह से डाउनलोड और एक्ज़ीक्यूट नहीं हो जाता या कोई भी वर्शन डाउनलोड नहीं हो जाता. हुर्रे! async-डाउनलोड करें लेकिन आदेश-प्रदर्शन!

इस तरीके से स्क्रिप्ट लोड करने में, Safari 5.0 (5.1) को छोड़कर, एसिंक एट्रिब्यूट के साथ काम करने वाली हर चीज़ काम करती है. इसके अलावा, Firefox और Opera के सभी वर्शन ऐसे वर्शन के रूप में काम करते हैं जो एसिंक्रोनस एट्रिब्यूट के साथ काम नहीं करते हैं. डाइनैमिक तौर पर जोड़ी गई स्क्रिप्ट, उसी क्रम में आसानी से एक्ज़ीक्यूट हो जाती हैं जिस क्रम में उन्हें दस्तावेज़ में जोड़ा जाता है.

क्या इस तरीके से स्क्रिप्ट को तुरंत लोड किया जा सकता है? है न?

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

इसे दस्तावेज़ में सबसे ऊपर रखकर, हम Google पर खोज के नतीजों को फिर से जोड़ सकते हैं:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

इससे ब्राउज़र को पता चलता है कि इस पेज के लिए 1.js और 2.js की ज़रूरत है. link[rel=subresource], link[rel=prefetch] से मिलता-जुलता है. हालांकि, इसके सिमेंटिक्स अलग होते हैं. माफ़ करें, फ़िलहाल यह सुविधा सिर्फ़ Chrome में ही काम करती है. इसके लिए, आपको यह एलान करना होगा कि कौनसी स्क्रिप्ट दो बार लोड करनी हैं, एक बार लिंक एलिमेंट के ज़रिए, और दूसरी बार अपनी स्क्रिप्ट में.

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

मुझे यह लेख निराशाजनक लगता है

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

<script src="dependencies.js"></script>
<script src="enhancement-1.js"></script>
<script src="enhancement-2.js"></script>
<script src="enhancement-3.js"></script>
…
<script src="enhancement-10.js"></script>

बेहतर बनाने की हर स्क्रिप्ट एक खास पेज कॉम्पोनेंट के साथ काम करती है, लेकिन डिपेंडेंसी.js में यूटिलिटी फ़ंक्शन की ज़रूरत होती है. आम तौर पर, हम सभी को एसिंक्रोनस रूप से डाउनलोड करना चाहते हैं. इसके बाद, उन्हें किसी भी क्रम में जल्द से जल्द एन्हैंसमेंट स्क्रिप्ट लागू करना चाहते हैं, लेकिन डिपेंडेंसी.js के बाद. यह धीरे-धीरे बेहतर होता जा रहा है! माफ़ करें, ऐसा करने का कोई एलान वाला तरीका तब तक नहीं है, जब तक डिपेंडेंसी.js की लोडिंग स्थिति को ट्रैक करने के लिए स्क्रिप्ट में खुद बदलाव न किया जाए. यहां तक कि async=false से भी इस समस्या का समाधान नहीं हो सकता, क्योंकि एन्हैंसमेंट-10.js का निष्पादन 1-9 तक ब्लॉक हो जाएगा. असल में, सिर्फ़ एक ही ब्राउज़र है जो बिना हैक के यह काम करने में मदद करता है...

आईई के पास एक सुझाव है!

IE, स्क्रिप्ट को दूसरे ब्राउज़र पर अलग तरीके से लोड करता है.

var script = document.createElement('script');
script.src = 'whatever.js';

IE अब “whatever.js” डाउनलोड करना शुरू कर देगा, अन्य ब्राउज़र तब तक डाउनलोड शुरू नहीं करेंगे जब तक कि स्क्रिप्ट को दस्तावेज़ में नहीं जोड़ दिया जाता. IE में एक इवेंट, “रेडीस्टेटचेंज”, और प्रॉपर्टी “रेडीस्टेट” भी है. इनसे हमें लोड होने की प्रोग्रेस के बारे में पता चलता है. यह वाकई में उपयोगी है, क्योंकि इसकी मदद से हम स्क्रिप्ट को लोड करने और उसे लागू करने का काम अलग-अलग कंट्रोल कर सकते हैं.

var script = document.createElement('script');

script.onreadystatechange = function() {
  if (script.readyState == 'loaded') {
    // Our script has download, but hasn't executed.
    // It won't execute until we do:
    document.body.appendChild(script);
  }
};

script.src = 'whatever.js';

हम कॉम्प्लेक्स डिपेंडेंसी मॉडल बना सकते हैं. इसके लिए, यह चुनना होगा कि दस्तावेज़ में स्क्रिप्ट कब जोड़नी हैं. IE ने इस मॉडल का वर्शन 6 से समर्थन किया है. थोड़ा दिलचस्प है, लेकिन इसे अब भी प्रीलोडर के खोजे जाने से जुड़ी वही समस्या आ रही है जो async=false ने की थी.

बहुत हो गया! मैं स्क्रिप्ट कैसे लोड करूं?

ठीक है, ठीक है. अगर स्क्रिप्ट को इस तरह लोड करना है कि रेंडरिंग ब्लॉक न हो, जिसमें दोहराव न हो, और ब्राउज़र के साथ काम करने की सुविधा बेहतर हो, तो मेरा सुझाव है:

<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>

यानी. शरीर तत्व के अंत में. हां, एक वेब डेवलपर होना बहुत कुछ किंग सिसाइफ़स होने जैसा है (बूम! ग्रीक पौराणिक कथाओं के बारे में बताने के लिए 100 हिप्स्टर पॉइंट!). एचटीएमएल और ब्राउज़र की सीमाएं हमें बेहतर काम करने में रुकावट डालती हैं.

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

ओह, ऐसा कुछ बेहतर होना चाहिए जिसका हम अब इस्तेमाल कर सकें?

काफ़ी सही, बोनस पॉइंट के लिए, अगर आपको परफ़ॉर्मेंस बेहतर करनी है और आपको चीज़ों को समझना और बार-बार दोहराना पड़ता है, तो आपके पास ऊपर दिए गए कुछ तरीके जोड़ने का विकल्प भी है.

सबसे पहले, हम प्रीलोडर के लिए सबरिसॉर्स का एलान करते हैं:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

इसके बाद, दस्तावेज़ के सबसे ऊपर इनलाइन रूप में, हम async=false का इस्तेमाल करके, JavaScript के साथ अपनी स्क्रिप्ट लोड करते हैं. हम IE की रेडीस्टेट-आधारित स्क्रिप्ट लोडिंग पर वापस आते हैं और डेफ़र में वापस आते हैं.

var scripts = [
  '1.js',
  '2.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we'll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

बाद में कुछ तरकीबें और काट-छांट करने की कोशिश करें. यह 362 बाइट का है + आपके स्क्रिप्ट यूआरएल:

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
  "//other-domain.com/1.js",
  "2.js"
])

क्या यह किसी सामान्य स्क्रिप्ट की तुलना में, ज़्यादा बाइट के लिए काम का है? अगर आपने शर्तों के साथ स्क्रिप्ट लोड करने के लिए, पहले से ही JavaScript का इस्तेमाल किया है, जैसा कि BBC करता है, तो इन डाउनलोड को पहले ही ट्रिगर करके आपको फ़ायदा मिल सकता है. अगर ऐसा नहीं है, तो शरीर को खत्म करने के आसान तरीके का इस्तेमाल करें.

ओह, अब मुझे पता है कि whatWG स्क्रिप्ट लोडिंग सेक्शन इतना विशाल क्यों है. मुझे एक ड्रिंक चाहिए.

झटपट रेफ़रंस

प्लेन स्क्रिप्ट के एलिमेंट

<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>

खास जानकारी के मुताबिक: एक साथ डाउनलोड करें, किसी भी बाकी सीएसएस के बाद एक क्रम में एक्ज़ीक्यूट करें, पूरा होने तक रेंडरिंग को ब्लॉक करें. ब्राउज़र्स ने कहा: हां सर!

स्थगित करें

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

खास जानकारी के मुताबिक: एक साथ डाउनलोड करें और DOMContentLoaded से ठीक पहले के क्रम में एक्ज़ीक्यूट करें. बिना “src” वाली स्क्रिप्ट पर “defer” को अनदेखा कर दें. IE < 10 का कहना है: शायद मैं 1.js के चलने के बीच में 2.js चला सकता हूं. है न मज़ेदार? लाल रंग में दिखाए गए ब्राउज़र का कहना है: मुझे नहीं पता कि यह “डिफ़र” क्या है. मैं स्क्रिप्ट को इस तरह लोड कर रहा हूं, जैसे कि वे पहले ही लोड न हों. दूसरे ब्राउज़र में कहा गया है: ठीक है, लेकिन शायद मैं “src” के बिना स्क्रिप्ट पर “defer” को अनदेखा न करूं.

Async

<script src="//other-domain.com/1.js" async></script>
<script src="2.js" async></script>

खास जानकारी के मुताबिक: एक साथ डाउनलोड करें और डाउनलोड किए जाने वाले क्रम में लागू करें. लाल रंग में दिखाए गए ब्राउज़र पर दिख रहा है: ‘एक साथ काम नहीं करने वाली प्रोसेस’ क्या है? मैं स्क्रिप्ट को इस तरह लोड कर रही हूं, जैसे कि वे पहले से ही मौजूद हों. दूसरे ब्राउज़र ने कहा: हां, ठीक है.

Async false

[
  '1.js',
  '2.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

खास जानकारी के मुताबिक: एक साथ डाउनलोड करें और सभी के डाउनलोड होने के बाद एक साथ डाउनलोड करें. Firefox < 3.6, Opera का कहना है: मुझे नहीं पता कि यह “एक साथ काम नहीं करने वाली प्रोसेस” क्या है, लेकिन ऐसा होता है, मैं JS से जोड़ी गई स्क्रिप्ट को उसी क्रम में चलाता हूं जिस क्रम में वे जोड़ी जाती हैं. Safari 5.0 के मुताबिक: मुझे “एक साथ काम नहीं करने वाली प्रोसेस” समझ है, लेकिन मुझे JS के साथ इसे “गलत” पर सेट करना नहीं आता. आपकी स्क्रिप्ट के लैंडिंग पेज पर, किसी भी क्रम में उन्हें चलाने के बाद, मैं उन्हें प्रोसेस कर दूँगी. IE < 10 में लिखा है: “एक साथ काम नहीं करने वाली प्रोसेस” के बारे में कोई जानकारी नहीं है, लेकिन “onरेडीस्टेटचेंज” का इस्तेमाल करने का एक समाधान है. दूसरे लाल रंग वाले ब्राउज़र का कहना है: मुझे यह “एक साथ काम नहीं करने वाली प्रोसेस” समझ नहीं आई, आपकी स्क्रिप्ट के लैंडिंग पेज पर, उसे किसी भी क्रम में लागू कर दिया जाएगा. बाकी सब कुछ लिखा है: मैं आपका दोस्त हूं और यह काम हम किताब के हिसाब से करेंगे.