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

Addy Osmani
Addy Osmani

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

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

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

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

इन तरीकों की मदद से, JavaScript की नेटवर्क ट्रांसफ़र लागत को कम किया जा सकता है:

  • सिर्फ़ वही कोड भेजना जो उपयोगकर्ता को चाहिए.
    • कोड-स्प्लिटिंग का इस्तेमाल करके, अपनी JavaScript को अलग-अलग हिस्सों में बांटें. इससे यह तय किया जा सकता है कि कौनसी चीज़ अहम है और कौनसी नहीं. मॉड्यूल बंडलर, जैसे कि webpack कोड-स्प्लिटिंग की सुविधा देते हैं.
    • ऐसे कोड में धीरे से लोड होना जो गैर-ज़रूरी है.
  • काट-छांट करना
  • कंप्रेस करना
    • कम से कम, gzip का इस्तेमाल करके टेक्स्ट वाले रिसॉर्स को कंप्रेस करें.
    • Bromli ~q11 का इस्तेमाल करें. Brotli, कंप्रेस करने के अनुपात में gzip की परफ़ॉर्मेंस से बेहतर है. इससे Crt Simple को कंप्रेस किए गए JS बाइट के साइज़ में 17% और LinkedIn को लोड होने में लगने वाले समय 4% की बचत करने में मदद मिली.
  • इस्तेमाल न होने वाले कोड को हटाना.
  • नेटवर्क ट्रिप कम करने के लिए कोड कैश मेमोरी में सेव करना.
    • यह पक्का करने के लिए कि ब्राउज़र रिस्पॉन्स को सही तरीके से कैश मेमोरी में सेव करे, एचटीटीपी कैश मेमोरी का इस्तेमाल करें. स्क्रिप्ट (मैक्स-एज) के लिए सबसे सही लाइफ़टाइम तय करें और पुष्टि करने वाले टोकन (ETag) उपलब्ध कराएं, ताकि बिना बदलाव की गई बाइट ट्रांसफ़र न हों.
    • सर्विस वर्कर कैश मेमोरी में सेव करने से, आपके ऐप्लिकेशन नेटवर्क को अपनी ज़रूरत के मुताबिक ढाला जा सकता है. साथ ही, इससे आपको V8 के कोड कैश जैसी सुविधाओं का तुरंत ऐक्सेस मिलता है.
    • जिन संसाधनों में कोई बदलाव नहीं हुआ है उन्हें फिर से फ़ेच करने से बचने के लिए, लंबे समय तक कैश मेमोरी का इस्तेमाल करें. अगर Webpack का इस्तेमाल किया जा रहा है, तो फ़ाइल नाम हैशिंग देखें.

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

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

ALT_TEXT_HERE

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

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

लेकिन, इससे फ़र्क क्यों पड़ता है?

ALT_TEXT_HERE

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

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

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

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

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

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

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

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

CNN.com जैसी किसी साइट पर क्या होगा?

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

ALT_TEXT_HERE
ऊपर हमने यह देखा है कि ज़्यादा औसत Android हार्डवेयर में Apple के A11 Bionic चिप की परफ़ॉर्मेंस Snapdragon 617 की परफ़ॉर्मेंस की तुलना करके कितना समय लगता है.

इससे सिर्फ़ आपकी जेब में रखे फ़ोन के बजाय, औसत हार्डवेयर (जैसे कि 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 (पुश, रेंडर, प्री-कैश, लेज़ी-लोड) एक ऐसा पैटर्न है जो कोड को ज़्यादा बारीकी से स्प्लिट और कैश मेमोरी में सेव करके, इंटरैक्टिविटी के लिए ऑप्टिमाइज़ करता है:

ALT_TEXT_HERE

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

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

ALT_TEXT_HERE

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

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

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

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

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

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

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

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

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

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

ALT_TEXT_HERE
इस बात पर ध्यान देना काफ़ी मददगार है कि JS "हेडरूम" के इस्तेमाल से जुड़े जो फ़ैसले हम लेते हैं वे ऐप्लिकेशन लॉजिक के लिए कितने काम के हो सकते हैं.

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

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