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

पार्स करना
डीओएम बनाना
जब रेंडरर प्रोसेस को नेविगेशन के लिए कमिट मैसेज मिलता है और एचटीएमएल डेटा मिलना शुरू होता है, तो मुख्य थ्रेड टेक्स्ट स्ट्रिंग (एचटीएमएल) को पार्स करना शुरू कर देती है और उसे Document Object Model (DOM) में बदल देती है.
डीओएम, ब्राउज़र में पेज के इंटरनल स्ट्रक्चर के साथ-साथ डेटा स्ट्रक्चर और एपीआई को दिखाता है. वेब डेवलपर, JavaScript की मदद से इनके साथ इंटरैक्ट कर सकता है.
एचटीएमएल दस्तावेज़ को DOM में पार्स करने के बारे में, एचटीएमएल स्टैंडर्ड में बताया गया है. आपने देखा होगा कि ब्राउज़र में एचटीएमएल फ़ीड करने पर, कभी भी गड़बड़ी नहीं होती. उदाहरण के लिए, क्लोज़िंग </p>
टैग मौजूद न होने पर भी एचटीएमएल मान्य होता है. Hi! <b>I'm <i>Chrome</b>!</i>
(i टैग से पहले b टैग बंद है) जैसे गलत मार्कअप को वैसे ही माना जाता है जैसे आपने Hi! <b>I'm <i>Chrome</i></b><i>!</i>
लिखा हो. ऐसा इसलिए है, क्योंकि एचटीएमएल स्पेसिफ़िकेशन को उन गड़बड़ियों को आसानी से मैनेज करने के लिए डिज़ाइन किया गया है. अगर आपको यह जानना है कि ये काम कैसे किए जाते हैं, तो एचटीएमएल स्पेसिफ़िकेशन के "पार्सर में गड़बड़ी को मैनेज करने और अजीब मामलों के बारे में जानकारी" सेक्शन को पढ़ें.
सब-सोर्स लोड करना
आम तौर पर, कोई वेबसाइट इमेज, सीएसएस, और JavaScript जैसे बाहरी रिसॉर्स का इस्तेमाल करती है. उन फ़ाइलों को नेटवर्क या कैश मेमोरी से डाउनलोड करना होगा. मुख्य थ्रेड, डीओएम बनाने के लिए पार्स करते समय, उन्हें ढूंढने के बाद एक-एक करके उनका अनुरोध कर सकता है. हालांकि, प्रोसेस को तेज़ करने के लिए, "प्रीलोड स्कैनर" एक साथ चलाया जाता है.
अगर एचटीएमएल दस्तावेज़ में <img>
या <link>
जैसी चीज़ें हैं, तो प्रीलोड स्कैनर, एचटीएमएल पार्स करने वाले टूल से जनरेट किए गए टोकन देखता है और ब्राउज़र प्रोसेस में नेटवर्क थ्रेड को अनुरोध भेजता है.

JavaScript, पार्स करने की प्रोसेस को ब्लॉक कर सकता है
जब एचटीएमएल पार्स करने वाले टूल को <script>
टैग मिलता है, तो वह एचटीएमएल दस्तावेज़ को पार्स करने की प्रोसेस रोक देता है. इसके बाद, उसे JavaScript कोड को लोड, पार्स, और एक्ज़ीक्यूट करना पड़ता है. क्यों? क्योंकि JavaScript, document.write()
जैसी चीज़ों का इस्तेमाल करके दस्तावेज़ का आकार बदल सकता है. इससे पूरे DOM स्ट्रक्चर में बदलाव होता है. एचटीएमएल स्पेसिफ़िकेशन में, पार्सिंग मॉडल की खास जानकारी वाला एक अच्छा डायग्राम है. इसलिए, एचटीएमएल दस्तावेज़ को पार्स करने के लिए, एचटीएमएल पार्सर को JavaScript के चलने का इंतज़ार करना पड़ता है. अगर आपको यह जानना है कि JavaScript को लागू करने के दौरान क्या होता है, तो V8 टीम ने इस बारे में बातचीत और ब्लॉग पोस्ट की हैं.
ब्राउज़र को यह बताना कि आपको संसाधनों को कैसे लोड करना है
वेब डेवलपर, रिसॉर्स को बेहतर तरीके से लोड करने के लिए ब्राउज़र को कई तरह के संकेत भेज सकते हैं.
अगर आपका JavaScript document.write()
का इस्तेमाल नहीं करता है, तो <script>
टैग में async
या defer
एट्रिब्यूट जोड़ा जा सकता है. इसके बाद, ब्राउज़र JavaScript कोड को एसिंक्रोनस तौर पर लोड और चलाता है. साथ ही, पार्सिंग को ब्लॉक नहीं करता. अगर आपके लिए JavaScript मॉड्यूल सही है, तो उसका भी इस्तेमाल किया जा सकता है. <link rel="preload">
का इस्तेमाल करके, ब्राउज़र को यह बताया जा सकता है कि मौजूदा नेविगेशन के लिए संसाधन ज़रूरी है और आपको उसे जल्द से जल्द डाउनलोड करना है. इस बारे में ज़्यादा जानने के लिए, संसाधनों को प्राथमिकता देना – ब्राउज़र की मदद लेना लेख पढ़ें.
स्टाइल का हिसाब लगाना
पेज कैसा दिखेगा, यह जानने के लिए सिर्फ़ DOM का होना काफ़ी नहीं है. ऐसा इसलिए है, क्योंकि हम सीएसएस में पेज एलिमेंट को स्टाइल कर सकते हैं. मुख्य थ्रेड, सीएसएस को पार्स करता है और हर डीओएम नोड के लिए कैलकुलेट की गई स्टाइल तय करता है. इससे यह जानकारी मिलती है कि सीएसएस सिलेक्टर के आधार पर, हर एलिमेंट पर किस तरह की स्टाइल लागू की गई है. यह जानकारी, DevTools के computed
सेक्शन में देखी जा सकती है.

भले ही आपने कोई सीएसएस न दी हो, फिर भी हर डीओएम नोड में एक स्टाइल होती है. <h1>
टैग, <h2>
टैग से बड़ा दिखता है. साथ ही, हर एलिमेंट के लिए मार्जिन तय किए जाते हैं. ऐसा इसलिए होता है, क्योंकि ब्राउज़र में डिफ़ॉल्ट स्टाइल शीट होती है. अगर आपको यह जानना है कि Chrome की डिफ़ॉल्ट सीएसएस कैसी है, तो सोर्स कोड यहां देखा जा सकता है.
लेआउट
अब रेंडरर प्रोसेस को दस्तावेज़ का स्ट्रक्चर और हर नोड की स्टाइल के बारे में पता है. हालांकि, किसी पेज को रेंडर करने के लिए, यह जानकारी काफ़ी नहीं है. मान लें कि आपको फ़ोन पर अपने दोस्त को किसी पेंटिंग के बारे में बताना है. "एक बड़ा लाल गोला और एक छोटा नीला वर्ग है", इस जानकारी से आपके दोस्त को यह पता नहीं चलेगा कि पेंटिंग कैसी दिखेगी.

लेआउट, एलिमेंट की ज्यामिति ढूंढने की प्रोसेस है. मुख्य थ्रेड, डीओएम और कैलकुलेट की गई स्टाइल के ज़रिए काम करता है. साथ ही, लेआउट ट्री बनाता है, जिसमें x y निर्देशांक और बॉर्डिंग बॉक्स के साइज़ जैसी जानकारी होती है. लेआउट ट्री का स्ट्रक्चर, डीओएम ट्री से मिलता-जुलता हो सकता है. हालांकि, इसमें सिर्फ़ पेज पर दिखने वाली जानकारी होती है. अगर display: none
लागू है, तो वह एलिमेंट लेआउट ट्री का हिस्सा नहीं है. हालांकि, visibility: hidden
वाला एलिमेंट लेआउट ट्री में होता है. इसी तरह, अगर p::before{content:"Hi!"}
जैसे कॉन्टेंट वाला कोई स्यूडो-एलिमेंट लागू किया जाता है, तो उसे लेआउट ट्री में शामिल किया जाता है. भले ही, वह डीओएम में न हो.

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

पेज को रेंडर करने के लिए, डीओएम, स्टाइल, और लेआउट का होना काफ़ी नहीं है. मान लें कि आपको किसी पेंटिंग को फिर से बनाने की कोशिश करनी है. आपको एलिमेंट का साइज़, आकार, और जगह पता है, लेकिन आपको यह तय करना होगा कि उन्हें किस क्रम में रंगना है.
उदाहरण के लिए, हो सकता है कि z-index
कुछ एलिमेंट के लिए सेट हो. ऐसे में, एचटीएमएल में लिखे गए एलिमेंट के क्रम में पेंटिंग करने पर, गलत रेंडरिंग होगी.

पेंट करने के इस चरण में, मुख्य थ्रेड, पेंट रिकॉर्ड बनाने के लिए लेआउट ट्री पर जाता है. पेंट रिकॉर्ड, पेंट करने की प्रोसेस का नोट होता है. जैसे, "पहले बैकग्राउंड, फिर टेक्स्ट, फिर रेक्टैंगल". अगर आपने JavaScript का इस्तेमाल करके <canvas>
एलिमेंट पर ड्रॉ किया है, तो हो सकता है कि आपको यह प्रोसेस पहले से पता हो.

रेंडरिंग पाइपलाइन को अपडेट करना महंगा होता है
रेंडरिंग पाइपलाइन में सबसे अहम बात यह समझना है कि हर चरण में, पिछले ऑपरेशन के नतीजे का इस्तेमाल नया डेटा बनाने के लिए किया जाता है. उदाहरण के लिए, अगर लेआउट ट्री में कोई बदलाव होता है, तो दस्तावेज़ के जिन हिस्सों पर असर पड़ा है उनके लिए, पेंट ऑर्डर को फिर से जनरेट करना होगा.
अगर एलिमेंट को ऐनिमेट किया जा रहा है, तो ब्राउज़र को हर फ़्रेम के बीच में ये कार्रवाइयां करनी होंगी. हमारे ज़्यादातर डिसप्ले, स्क्रीन को हर सेकंड में 60 बार रीफ़्रेश करते हैं (60 fps); जब हर फ़्रेम में स्क्रीन पर चीज़ें मूव की जाती हैं, तो ऐनिमेशन लोगों को स्मूद दिखेगा. हालांकि, अगर ऐनिमेशन के बीच में फ़्रेम नहीं दिखते हैं, तो पेज "अजीब" दिखेगा.

भले ही, रेंडरिंग की प्रोसेस स्क्रीन रीफ़्रेश के साथ-साथ चल रही हो, लेकिन ये कैलकुलेशन मुख्य थ्रेड पर चल रहे हैं. इसका मतलब है कि जब आपका ऐप्लिकेशन JavaScript चला रहा हो, तो इसे ब्लॉक किया जा सकता है.

JavaScript ऑपरेशन को छोटे-छोटे हिस्सों में बांटा जा सकता है और requestAnimationFrame()
का इस्तेमाल करके, हर फ़्रेम में चलाने के लिए शेड्यूल किया जा सकता है. इस विषय के बारे में ज़्यादा जानने के लिए, कृपया JavaScript एक्सीक्यूशन को ऑप्टिमाइज़ करना देखें. मुख्य थ्रेड को ब्लॉक होने से बचाने के लिए, JavaScript को वेब वर्कर्स में भी चलाया जा सकता है.

कंपोज़िट करना
पेज को कैसे ड्रॉ किया जाता है?
अब जब ब्राउज़र को दस्तावेज़ का स्ट्रक्चर, हर एलिमेंट का स्टाइल, पेज की ज्यामिति, और पेज को पेंट करने का क्रम पता है, तो वह पेज को कैसे ड्रॉ करता है? इस जानकारी को स्क्रीन पर पिक्सल में बदलने को रेस्टर करने के लिए कहा जाता है.
शायद इसे मैनेज करने का एक आसान तरीका यह हो कि व्यूपोर्ट में मौजूद हिस्सों को रेस्टर किया जाए. अगर कोई उपयोगकर्ता पेज को स्क्रोल करता है, तो रेस्टर किए गए फ़्रेम को मूव करें और ज़्यादा रेस्टर करके, छूटे हुए हिस्सों को भरें. Chrome के पहली बार रिलीज़ होने पर, रेस्टर करने की प्रोसेस इस तरह से होती थी. हालांकि, आधुनिक ब्राउज़र, कॉम्पोज़ करने की ज़्यादा बेहतर प्रोसेस का इस्तेमाल करता है.
कॉम्पोज़िटिंग क्या है
कॉम्पोज़िटिंग एक ऐसी तकनीक है जिसकी मदद से पेज के अलग-अलग हिस्सों को लेयर में बांटा जाता है, उन्हें अलग-अलग रेस्टर किया जाता है, और कॉम्पोज़िटर थ्रेड नाम की अलग थ्रेड में पेज के तौर पर कॉम्पोज़ किया जाता है. अगर स्क्रोल किया जाता है, तो लेयर पहले से ही रेस्टर की गई होती हैं. इसलिए, उसे सिर्फ़ एक नया फ़्रेम कंपोज करना होता है. लेयर को एक जगह से दूसरी जगह ले जाकर और नया फ़्रेम कंपोज करके भी ऐनिमेशन बनाया जा सकता है.
लेयर पैनल का इस्तेमाल करके, यह देखा जा सकता है कि DevTools में आपकी वेबसाइट को लेयर में कैसे बांटा गया है.
लेयर में बांटना
यह पता लगाने के लिए कि किन एलिमेंट को किन लेयर में रखना है, मुख्य थ्रेड लेयर ट्री बनाने के लिए लेआउट ट्री को स्कैन करता है. DevTools के परफ़ॉर्मेंस पैनल में, इस हिस्से को "लेयर ट्री अपडेट करें" कहा जाता है. अगर किसी पेज के कुछ हिस्सों को अलग लेयर (जैसे कि स्लाइड-इन साइड मेन्यू) के तौर पर नहीं दिखाया जा रहा है, तो सीएसएस में will-change
एट्रिब्यूट का इस्तेमाल करके, ब्राउज़र को इसकी जानकारी दी जा सकती है.

हो सकता है कि आप हर एलिमेंट को लेयर दें, लेकिन ज़्यादा लेयर में कॉम्पोज़ करने से, हर फ़्रेम में पेज के छोटे हिस्सों को रेस्टर करने की तुलना में, काम धीमा हो सकता है. इसलिए, यह ज़रूरी है कि आप अपने ऐप्लिकेशन की रेंडरिंग परफ़ॉर्मेंस को मेज़र करें. विषय के बारे में ज़्यादा जानने के लिए, सिर्फ़ कंपोजिटर प्रॉपर्टी का इस्तेमाल करें और लेयर की संख्या मैनेज करें लेख पढ़ें.
मुख्य थ्रेड से रेस्टर और कंपोजिट हटाना
लेयर ट्री बन जाने और पेंट ऑर्डर तय होने के बाद, मुख्य थ्रेड उस जानकारी को कंपोजिटर थ्रेड में डाल देता है. इसके बाद, कंपोजिटर थ्रेड हर लेयर को रेस्टर करता है. कोई लेयर, पेज की पूरी लंबाई के बराबर बड़ी हो सकती है. इसलिए, कंपोजिटर थ्रेड उन्हें टाइल में बांटती है और हर टाइल को रेस्टर थ्रेड पर भेजती है. रेस्टर थ्रेड, हर टाइल को रेस्टर में बदलते हैं और उन्हें GPU की स्मृति में सेव करते हैं.

कंपोजिटर थ्रेड, अलग-अलग रेस्टर थ्रेड को प्राथमिकता दे सकता है, ताकि व्यूपोर्ट (या आस-पास) में मौजूद चीज़ों को पहले रेस्टर किया जा सके. ज़ूम-इन जैसी कार्रवाइयों को मैनेज करने के लिए, लेयर में अलग-अलग रिज़ॉल्यूशन के लिए कई टाइल भी होती हैं.
टाइल रेस्टर होने के बाद, कंपोजिटर थ्रेड कंपोजिटर फ़्रेम बनाने के लिए, ड्रॉ क्वॉड नाम की टाइल की जानकारी इकट्ठा करती है.
क्वाड ड्रॉ करना | इसमें मेमोरी में टाइल की जगह और पेज में टाइल को कहां दिखाना है, जैसे अहम जानकारी होती है. |
कंपोज़िटर फ़्रेम | ड्रॉ क्वाड का कलेक्शन, जो किसी पेज के फ़्रेम को दिखाता है. |
इसके बाद, कंपोजिटर फ़्रेम को आईपीसी के ज़रिए ब्राउज़र प्रोसेस में सबमिट किया जाता है. इस समय, ब्राउज़र के यूज़र इंटरफ़ेस (यूआई) में बदलाव करने के लिए, यूज़र इंटरफ़ेस (यूआई) थ्रेड से एक और कंपोजिटर फ़्रेम जोड़ा जा सकता है. इसके अलावा, एक्सटेंशन के लिए, रेंडरर करने की अन्य प्रोसेस से भी ऐसा किया जा सकता है. इन कंपोजिटर फ़्रेम को स्क्रीन पर दिखाने के लिए, जीपीयू (GPU) को भेजा जाता है. अगर कोई स्क्रोल इवेंट आता है, तो कंपोजिटर थ्रेड, जीपीयू को भेजने के लिए एक और कंपोजिटर फ़्रेम बनाता है.

कॉम्पोज़ करने का फ़ायदा यह है कि यह मुख्य थ्रेड के बिना किया जाता है. कंपोजिटर थ्रेड को स्टाइल कैलकुलेशन या JavaScript के लागू होने का इंतज़ार नहीं करना पड़ता. इसलिए, बेहतर परफ़ॉर्मेंस के लिए सिर्फ़ ऐनिमेशन को कॉम्पोज़ करना सबसे अच्छा माना जाता है. अगर लेआउट या पेंट को फिर से कैलकुलेट करना है, तो मुख्य थ्रेड को शामिल करना होगा.
आखिर में खास जानकारी
इस पोस्ट में, हमने पार्स करने से लेकर कंपोज करने तक की रेंडरिंग पाइपलाइन के बारे में बताया है. हमें उम्मीद है कि अब आपके पास, वेबसाइट की परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के बारे में ज़्यादा पढ़ने का विकल्प है.
इस सीरीज़ की अगली और आखिरी पोस्ट में, हम कॉम्पोज़र थ्रेड के बारे में ज़्यादा जानकारी देंगे. साथ ही, यह भी देखेंगे कि mouse move
और click
जैसे उपयोगकर्ता इनपुट मिलने पर क्या होता है.
क्या आपको यह पोस्ट पसंद आई? अगर आने वाले समय में पोस्ट के लिए आपका कोई सवाल या सुझाव है, तो हमें बताएं. इसके लिए, नीचे दिए गए टिप्पणी वाले सेक्शन में या Twitter पर @kosamari पर हमसे संपर्क करें.