ग़ैर-ज़रूरी पेंट से बचना

परिचय

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

पेंटिंग: खास जानकारी

ब्राउज़र को कई काम करने होते हैं. इनमें से एक मुख्य काम, आपके डीओएम और सीएसएस को स्क्रीन पर पिक्सल में बदलना है. यह काम, ब्राउज़र एक काफ़ी जटिल प्रोसेस के ज़रिए करता है. यह मार्कअप को पढ़कर शुरू होता है और इससे डीओएम ट्री बनाता है. यह सीएसएस के साथ भी ऐसा ही करता है और इससे सीएसएसओएम बनाता है. इसके बाद, DOM और CSSOM को आपस में जोड़ दिया जाता है. आखिर में, हमें एक ऐसा स्ट्रक्चर मिलता है जिससे कुछ पिक्सल पेंट किए जा सकते हैं.

पेंटिंग की प्रक्रिया ही दिलचस्प होती है. Chrome में DOM और CSS के मिले-जुले ट्री को Skia नाम के कुछ सॉफ़्टवेयर की मदद से रास्टराइज़ किया जाता है. अगर आपने कभी canvas एलिमेंट के साथ काम किया है, तो आपको Skia का एपीआई बहुत जाना-पहचाना लगेगा. इसमें moveTo और lineTo स्टाइल के कई फ़ंक्शन के साथ-साथ, कई बेहतर फ़ंक्शन भी हैं. जिन एलिमेंट को पेंट करना है उन्हें Skia कॉल के कलेक्शन में डाला जाता है, ताकि उन्हें चलाया जा सके. इन एलिमेंट का आउटपुट बिटमैप का एक ग्रुप होता है. ये बिटमैप जीपीयू पर अपलोड किए जाते हैं और जीपीयू इन्हें एक साथ जोड़कर स्क्रीन पर हमें पूरी तरह से दिखाता है.

डॉम से पिक्सल

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

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

स्क्रोल करना

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

यह देखने के लिए कि किन हिस्सों को फिर से रंगा जा रहा है, Chrome के DevTools में “पेंट किए गए रेक्टैंगल दिखाएं” सुविधा का इस्तेमाल किया जा सकता है. इसके लिए, सबसे नीचे दाएं कोने में मौजूद छोटे कॉग पर क्लिक करें. इसके बाद, DevTools खोलकर अपने पेज पर इंटरैक्ट करें. आपको फ़्लैश करने वाले रेक्टैंगल दिखेंगे. इनसे पता चलेगा कि Chrome ने आपके पेज के किस हिस्से को कब और कहां पेंट किया है.

Chrome DevTools में पेंट रेक्टैंगल दिखाना
Chrome DevTools में पेंट रेक्टैंगल दिखाना

आपकी साइट की परफ़ॉर्मेंस के लिए, स्क्रोलिंग की परफ़ॉर्मेंस काफ़ी अहम है. जब आपकी साइट या ऐप्लिकेशन ठीक से स्क्रोल नहीं होता, तो उपयोगकर्ताओं को यह बहुत बुरा लगता है. इसलिए, हमारी दिलचस्पी है कि स्क्रोल करने के दौरान, पेज पर ज़्यादा बदलाव न हों, ताकि उपयोगकर्ताओं को झटका न लगे.

मैंने पहले स्क्रोल करने की परफ़ॉर्मेंस के बारे में एक लेख लिखा था. अगर आपको स्क्रोल करने की परफ़ॉर्मेंस के बारे में ज़्यादा जानना है, तो उस लेख को पढ़ें.

इंटरैक्शन

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

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

एक दुर्भाग्यपूर्ण कॉम्बिनेशन

महंगे पेंट के साथ डेमो
ऐसा डेमो जिसमें महंगे पेंट इस्तेमाल किए गए हों

अगर मैं एक ही समय पर स्क्रोल और माउस को मूव करूं, तो क्या होगा? ऐसा हो सकता है कि मैं किसी एलिमेंट से अनजाने में "बातचीत" कर पाऊँ. इस दौरान, मैंने उस एलिमेंट को पीछे से स्क्रोल कर लिया. इससे एक महंगा पेंट ट्रिगर हो गया. इससे, मुझे अपने फ़्रेम बजट के 16.7 मिलीसेकंड तक पहुंचने में मदद मिल सकती है. हर सेकंड 60 फ़्रेम पाने के लिए, हमें इस समयसीमा के अंदर रहना होगा. मैंने एक डेमो बनाया है, ताकि आपको पता चल सके कि मेरा मतलब क्या है. उम्मीद है कि स्क्रोल करने और माउस को घुमाने पर, आपको कर्सर घुमाने पर दिखने वाले इफ़ेक्ट दिखेंगे. हालांकि, यह देखना दिलचस्प होगा कि Chrome के DevTools में इन इफ़ेक्ट का क्या असर पड़ता है:

Chrome के DevTools में, ज़्यादा डेटा खर्च करने वाले फ़्रेम दिख रहे हैं
Chrome DevTools में महंगे फ़्रेम दिखना

ऊपर दी गई इमेज में देखा जा सकता है कि जब किसी ब्लॉक पर कर्सर घुमाया जाता है, तो DevTools पेंट करने की प्रोसेस को रजिस्टर कर रहा है. मैंने अपने डेमो में कुछ सुपर हेवी स्टाइल इस्तेमाल किए हैं, ताकि यह बात साफ़ तौर पर बताई जा सके. इसलिए, मैं अपने फ़्रेम बजट को बढ़ा रहा हूं और कभी-कभी उससे ज़्यादा भी इस्तेमाल कर रहा हूं. मुझे इस तरह का काम बिलकुल नहीं करना है. खास तौर पर, स्क्रोल करते समय, जब कोई और काम करना हो!

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

कोड यहां दिया गया है:

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

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

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {
 
}

बस इतना ही!

नतीजा

आपके ऐप्लिकेशन का आनंद लेने के लिए, रेंडरिंग की परफ़ॉर्मेंस का होना ज़रूरी है. इसलिए, आपको हमेशा अपने पेन्ट वर्कलोड को 16 मिलीसेकंड से कम रखने की कोशिश करनी चाहिए. ऐसा करने के लिए, आपको अपनी डेवलपमेंट प्रोसेस के दौरान DevTools का इस्तेमाल करते रहना चाहिए. इससे अड़चनें पैदा होने पर उनकी पहचान करके उन्हें ठीक किया जा सकता है.

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

अपनी साइटों और ऐप्लिकेशन पर नज़र डालें. क्या उन्हें थोड़ी सुरक्षा की ज़रूरत है?