JavaScript स्टार्ट-अप ऑप्टिमाइज़ेशन

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

नेटवर्क

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

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

इससे समस्या हो सकती है, क्योंकि हो सकता है कि उपयोगकर्ता के पास असल में 3G, 4G या वाई-फ़ाई के बजाय, नेटवर्क कनेक्शन का कोई और टाइप हो. हो सकता है कि आप कॉफ़ी शॉप के वाई-फ़ाई से कनेक्ट हों, लेकिन मोबाइल नेटवर्क के हॉटस्पॉट से 2G स्पीड पर कनेक्ट हों.

JavaScript के नेटवर्क ट्रांसफ़र की लागत को कम करने के लिए, ये काम करें:

  • सिर्फ़ वह कोड भेजना जिसकी उपयोगकर्ता को ज़रूरत है.
  • छोटा करना
    • ES5 कोड को छोटा करने के लिए, UglifyJS का इस्तेमाल करें.
    • ES2015 और उसके बाद के वर्शन को छोटा करने के लिए, babel-minify या uglify-es का इस्तेमाल करें.
  • कंप्रेस करना
    • टेक्स्ट पर आधारित संसाधनों को कम से कम, gzip का इस्तेमाल करके कंप्रेस करें.
    • Brotli~q11 का इस्तेमाल करें. Brotli, कंप्रेशन रेशियो के मामले में gzip से बेहतर परफ़ॉर्म करता है. इससे CertSimple को, संपीड़ित JS बाइट के साइज़ में 17% और LinkedIn को लोड होने में लगने वाले समय में 4% की बचत करने में मदद मिली.
  • इस्तेमाल न किए गए कोड हटाना.
    • DevTools कोड कवरेज की मदद से, ऐसे कोड की पहचान करें जिसे हटाया जा सकता है या जिसे ज़रूरत पड़ने पर लोड किया जा सकता है.
    • नए ब्राउज़र में पहले से मौजूद सुविधाओं को ट्रांसपाइल करने से बचने के लिए, babel-preset-env और ब्राउज़र की सूची का इस्तेमाल करें. बेहतर डेवलपर को अपने वेबपैक बंडल का ध्यान से विश्लेषण करने से, ज़रूरत न पड़ने वाली डिपेंडेंसी को कम करने के अवसरों की पहचान करने में मदद मिल सकती है.
    • कोड हटाने के लिए, ट्री-शैकिंग, Closure Compiler के बेहतर ऑप्टिमाइज़ेशन, और लाइब्रेरी को छोटा करने वाले प्लगिन देखें. जैसे, Moment.js जैसी लाइब्रेरी के लिए, lodash-babel-plugin या webpack का ContextReplacementPlugin.
  • नेटवर्क ट्रिप को कम करने के लिए, कोड को कैश मेमोरी में सेव करना.
    • एचटीटीपी कैश मेमोरी का इस्तेमाल करके, पक्का करें कि ब्राउज़र जवाबों को असरदार तरीके से कैश मेमोरी में सेव करें. स्क्रिप्ट (max-age) के लिए सबसे सही लाइफ़टाइम तय करें और पुष्टि करने वाले टोकन (ETag) की आपूर्ति करें, ताकि बिना बदलाव वाले बाइट को ट्रांसफ़र करने से बचा जा सके.
    • सर्विस वर्कर कैश मेमोरी की मदद से, आपके ऐप्लिकेशन के नेटवर्क को बेहतर बनाया जा सकता है. साथ ही, आपको V8 के कोड कैश मेमोरी जैसी सुविधाओं का तुरंत ऐक्सेस मिल सकता है.
    • लंबे समय तक कैश मेमोरी में सेव रखने का तरीका इस्तेमाल करें, ताकि आपको ऐसे संसाधनों को फिर से फ़ेच न करना पड़े जिनमें कोई बदलाव नहीं हुआ है. अगर Webpack का इस्तेमाल किया जा रहा है, तो फ़ाइल का नाम हैश करना देखें.

पार्स/कंपाइल करना

डाउनलोड होने के बाद, JavaScript कोड को पार्स/कंपाइल करने में JS इंजन को ज़्यादा समय लगता है. यह समय, JavaScript के लिए सबसे ज़्यादा खर्च होता है. Chrome DevTools में, पार्स और कंपाइल करने में लगने वाला समय, परफ़ॉर्मेंस पैनल में पीले रंग के "स्क्रिप्टिंग" समय में शामिल होता है.

ALT_TEXT_HERE

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

ALT_TEXT_HERE
Chrome DevTools के परफ़ॉर्मेंस पैनल > बॉटम-अप पर जाएं. V8 के रनटाइम कॉल के आंकड़े चालू होने पर, हम पार्स और कंपाइल जैसे चरणों में बिताए गए समय को देख सकते हैं

लेकिन, यह क्यों ज़रूरी है?

ALT_TEXT_HERE

कोड को पार्स/कंपाइल करने में ज़्यादा समय लगने पर, उपयोगकर्ता को आपकी साइट के साथ इंटरैक्ट करने में काफ़ी देरी हो सकती है. जितने ज़्यादा JavaScript भेजे जाएंगे, उतना ही ज़्यादा समय आपकी साइट को इंटरैक्टिव होने से पहले, उसे पार्स और कंपाइल करने में लगेगा.

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

JavaScript की तुलना में, एक जैसी साइज़ वाली इमेज को प्रोसेस करने में कई तरह की लागत आती है. इन्हें अब भी डिकोड करना पड़ता है! हालांकि, औसत मोबाइल हार्डवेयर पर, JS से पेज की इंटरैक्टिविटी पर बुरा असर पड़ने की संभावना ज़्यादा होती है.

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

पार्स और कंपाइल करने में लगने वाले समय के बारे में बात करते समय, संदर्भ ज़रूरी है — हम यहां औसत मोबाइल फ़ोन के बारे में बात कर रहे हैं. आम तौर पर, लोगों के पास ऐसे फ़ोन हो सकते हैं जिनमें धीमे सीपीयू और जीपीयू हों, L2/L3 कैश मेमोरी न हो, और जिनमें मेमोरी की कमी भी हो सकती है.

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

यहां हम कम और हाई-एंड हार्डवेयर पर, डिकंप्रेस किए गए (साधारण) JavaScript के ~1 एमबी को पार्स करने में लगने वाले समय को देख सकते हैं. बाज़ार में मौजूद सबसे तेज़ फ़ोन और औसत फ़ोन के बीच, कोड को पार्स/कंपाइल करने में लगने वाले समय में 2 से 5 गुना का अंतर होता है.

ALT_TEXT_HERE
इस ग्राफ़ में, अलग-अलग क्लास के डेस्कटॉप और मोबाइल डिवाइसों पर, 1 एमबी के JavaScript बंडल (~250 केबी के ज़िप किए गए) को पार्स करने में लगने वाले समय को हाइलाइट किया गया है. पार्स करने की लागत का आकलन करते समय, डिकंप्रेस किए गए आंकड़े देखे जाते हैं.उदाहरण के लिए, ~250 केबी का ज़िप किया गया JS, ~1 एमबी के कोड में डिकंप्रेस हो जाता है.

CNN.com जैसी असल साइट के लिए क्या होगा?

iPhone 8 जैसे बेहतर फ़ोन पर, CNN के JS को पार्स/कंपाइल करने में सिर्फ़ ~4 सेकंड लगते हैं. वहीं, सामान्य फ़ोन (Moto G4) पर, ऐसा करने में ~13 सेकंड लगते हैं. इससे इस बात पर काफ़ी असर पड़ सकता है कि कोई उपयोगकर्ता इस साइट के साथ कितनी तेज़ी से इंटरैक्ट कर सकता है.

ALT_TEXT_HERE
ऊपर दिए गए टेबल में, पार्स करने में लगने वाले समय की तुलना की गई है. इसमें, Apple की A11 Bionic चिप की परफ़ॉर्मेंस की तुलना, Snapdragon 617 से की गई है. Snapdragon 617, आम तौर पर इस्तेमाल होने वाले Android हार्डवेयर में इस्तेमाल की जाती है.

इससे पता चलता है कि सिर्फ़ अपनी जेब में मौजूद फ़ोन के बजाय, औसत हार्डवेयर (जैसे, Moto G4) पर टेस्ट करना ज़रूरी है. हालांकि, कॉन्टेक्स्ट का फ़र्क़ पड़ता है: अपने उपयोगकर्ताओं के डिवाइस और नेटवर्क की स्थिति के हिसाब से ऑप्टिमाइज़ करें.

ALT_TEXT_HERE
Google Analytics, मोबाइल डिवाइस की उन क्लास के बारे में अहम जानकारी दे सकता है जिनका इस्तेमाल करके आपके असली उपयोगकर्ता आपकी साइट को ऐक्सेस कर रहे हैं. इससे, सीपीयू/जीपीयू की उन असली समस्याओं को समझने में मदद मिल सकती है जिनसे डिवाइस काम कर रहा है.

क्या हम ज़्यादा JavaScript भेज रहे हैं? शायद :)

मोबाइल पर JavaScript की स्थिति का विश्लेषण करने के लिए, एचटीटीपी संग्रह (5 लाख की सबसे लोकप्रिय साइटें) का इस्तेमाल करके, हमने पाया कि 50% साइटों को इंटरैक्टिव होने में 14 सेकंड से ज़्यादा समय लगता है. ये साइटें, JS को पार्स और कंपाइल करने में चार सेकंड तक का समय लेती हैं.

ALT_TEXT_HERE

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

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

लागू होने में लगने वाला समय

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

ALT_TEXT_HERE

अगर स्क्रिप्ट 50 मि॰से॰ से ज़्यादा समय तक चलती है, तो इंटरैक्टिव में लगने वाला समय, JS को डाउनलोड करने, कंपाइल करने, और उसे चलाने में लगने वाले पूरे समय के बराबर बढ़ जाता है — ऐलेक्स रसेल

इस समस्या को हल करने के लिए, JavaScript को छोटे-छोटे हिस्सों में बांटा जाता है, ताकि मुख्य थ्रेड को लॉक होने से बचाया जा सके. देखें कि क्या प्रोसेस के दौरान किए जा रहे काम को कम किया जा सकता है.

अन्य लागतें

JavaScript, पेज की परफ़ॉर्मेंस पर इन तरीकों से भी असर डाल सकता है:

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

JavaScript डिलीवरी की लागत कम करने के पैटर्न

JavaScript को पार्स/कंपाइल करने और नेटवर्क पर भेजने में लगने वाले समय को कम करने के लिए, कुछ पैटर्न का इस्तेमाल किया जा सकता है. जैसे, रास्ते के हिसाब से चंक करना या PRPL.

PRPL

PRPL (पुश, रेंडर, प्री-कैश, लेज़ी-लोड) एक ऐसा पैटर्न है जो कोड को अलग-अलग हिस्सों में बांटने और कैश मेमोरी में सेव करने की सुविधा की मदद से, इंटरैक्टिविटी को ऑप्टिमाइज़ करता है:

ALT_TEXT_HERE

आइए, देखते हैं कि इसका क्या असर हो सकता है.

हम V8 के रनटाइम कॉल के आंकड़ों का इस्तेमाल करके, लोकप्रिय मोबाइल साइटों और प्रोग्रेसिव वेब ऐप्लिकेशन के लोड होने में लगने वाले समय का विश्लेषण करते हैं. जैसा कि हम देख सकते हैं, इनमें से कई साइटें, ऑरेंज रंग में दिखाए गए पार्स करने में लगने वाले समय पर काफ़ी समय बिताती हैं:

ALT_TEXT_HERE

Wego, PRPL का इस्तेमाल करने वाली साइट है. यह अपने रास्तों के लिए कम पार्स समय बनाए रखती है और बहुत तेज़ी से इंटरैक्टिव हो जाती है. ऊपर दी गई कई अन्य साइटों ने कोड-स्प्लिटिंग और परफ़ॉर्मेंस बजट का इस्तेमाल किया है, ताकि वे JS की लागत कम कर सकें.

प्रोग्रेसिव बूटस्ट्रैपिंग

कई साइटें, इंटरैक्टिविटी की कीमत पर कॉन्टेंट की विज़िबिलिटी को ऑप्टिमाइज़ करती हैं. जब आपके पास बड़े JavaScript बंडल हों, तो तेज़ी से पेज का पहला हिस्सा दिखने के लिए, डेवलपर कभी-कभी सर्वर-साइड रेंडरिंग का इस्तेमाल करते हैं. इसके बाद, JavaScript फ़ेच होने के बाद, इवेंट हैंडलर को अटैच करने के लिए, इसे "अपग्रेड" करते हैं.

ध्यान रखें — इसकी अलग से कीमत होती है. 1) आम तौर पर, बड़ा एचटीएमएल रिस्पॉन्स भेजा जाता है, जिससे इंटरैक्टिविटी बढ़ सकती है. 2) उपयोगकर्ता को ऐसी स्थिति में छोड़ा जा सकता है जहां JavaScript प्रोसेसिंग पूरी होने तक, आधे अनुभव में इंटरैक्टिविटी नहीं हो सकती.

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

ALT_TEXT_HERE
प्रोग्रेसिव बूटस्ट्रैपिंग, पॉल लुइस की लेख

व्यू में मौजूद कॉन्टेंट के हिसाब से कोड लोड करना, सबसे बेहतर तरीका है. PRPL और प्रोग्रेसिव बूटस्ट्रैपिंग ऐसे पैटर्न हैं जिनकी मदद से, यह काम किया जा सकता है.

मीटिंग में सामने आए नतीजे

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

टीमों को परफ़ॉर्मेंस के सख्त बजट को अपनाने से सफलता मिली है. इससे, JavaScript ट्रांसमिशन और पार्स/कंपाइल करने में लगने वाला समय कम हो गया है. एलेक्स रसेल की "क्या आपके पास इसके लिए पैसे हैं?: असल दुनिया में वेब की परफ़ॉर्मेंस के लिए तय किए गए बजट" पढ़ें.

ALT_TEXT_HERE
यह जानना ज़रूरी है कि आर्किटेक्चर से जुड़े फ़ैसले लेने पर, ऐप्लिकेशन के लॉजिक के लिए JS में कितना "हेडरूम" बच सकता है.

अगर आपको मोबाइल डिवाइसों को टारगेट करने वाली साइट बनानी है, तो कोशिश करें कि आप इसे सही हार्डवेयर पर डेवलप करें. साथ ही, JavaScript को पार्स/कंपाइल करने में लगने वाले समय को कम रखें. इसके अलावा, परफ़ॉर्मेंस बजट का इस्तेमाल करें, ताकि आपकी टीम JavaScript की लागत पर नज़र रख सके.

ज़्यादा जानें