आधुनिक वेब ब्राउज़र के बारे में जानकारी (भाग 3)

Mariko Kosaka

रेंडर करने की प्रोसेस के बारे में अंदरूनी जानकारी

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

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

रेंडर करने वाली प्रोसेस, वेब कॉन्टेंट को हैंडल करती हैं

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

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

रेंडर करने की प्रोसेस
पहली इमेज: मुख्य थ्रेड, वर्कर थ्रेड, कंपोज़िटर थ्रेड, और रास्टर थ्रेड के साथ रेंडर करने की प्रोसेस

पार्स करना

डीओएम बनाना

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

डीओएम, ब्राउज़र के पेज के साथ-साथ डेटा स्ट्रक्चर और एपीआई को दिखाता है, जिसके साथ वेब डेवलपर JavaScript की मदद से इंटरैक्ट कर सकता है.

एचटीएमएल दस्तावेज़ को डीओएम में पार्स करने का तरीका, एचटीएमएल स्टैंडर्ड तय करता है. आपने देखा होगा कि किसी ब्राउज़र में HTML फ़ीड करने में कभी भी गड़बड़ी नहीं आती. उदाहरण के लिए, बंद होने वाला </p> टैग एक मान्य एचटीएमएल है. गड़बड़ी वाले मार्कअप जैसे कि Hi! <b>I'm <i>Chrome</b>!</i> (b टैग, i टैग से पहले बंद हो जाता है) को ठीक वैसा ही माना जाता है जैसा आपने लिखा है Hi! <b>I'm <i>Chrome</i></b><i>!</i>. ऐसा इसलिए होता है क्योंकि एचटीएमएल की विशेषताओं को इस तरह डिज़ाइन किया गया है कि वे गड़बड़ियों को आसानी से हैंडल कर सकें. अगर आपको यह जानना है कि ये काम कैसे किए जाते हैं, तो एचटीएमएल स्पेसिफ़िकेशन के "पार्सर में गड़बड़ियों को ठीक करने और असामान्य मामलों के बारे में जानकारी" सेक्शन पढ़ें.

सबरिसॉर्स लोड हो रहे हैं

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

डीओएम
इमेज 2: एचटीएमएल को पार्स करने वाला मुख्य थ्रेड और डीओएम ट्री बनाना

JavaScript, पार्स करने को ब्लॉक कर सकता है

जब एचटीएमएल पार्सर को <script> टैग मिलता है, तो यह एचटीएमएल दस्तावेज़ की पार्सिंग रोक देता है. साथ ही, उसे JavaScript कोड को लोड, पार्स, और लागू करना पड़ता है. ऐसा क्यों? क्योंकि JavaScript, document.write() जैसी चीज़ों का इस्तेमाल करके दस्तावेज़ का आकार बदल सकता है. इससे पूरे डीओएम स्ट्रक्चर में बदलाव होता है (एचटीएमएल स्पेसिफ़िकेशन में पार्स करने के मॉडल की खास जानकारी का डायग्राम अच्छा है). इसी वजह से, एचटीएमएल दस्तावेज़ को पार्स करना फिर से शुरू करने से पहले, एचटीएमएल पार्सर को JavaScript के चलने का इंतज़ार करना पड़ता है. अगर आपको यह जानना है कि JavaScript लागू करने में क्या होता है, तो V8 की टीम ने इस बारे में बातचीत और ब्लॉग पोस्ट की हैं.

ब्राउज़र को संकेत दें कि आप संसाधनों को किस तरह लोड करना चाहते हैं

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

स्टाइल का कैलकुलेशन

पेज कैसा दिखेगा, यह जानने के लिए डीओएम होना काफ़ी नहीं है, क्योंकि हम सीएसएस में पेज एलिमेंट को स्टाइल कर सकते हैं. मुख्य थ्रेड सीएसएस को पार्स करता है और हर डीओएम नोड के लिए कंप्यूट की गई स्टाइल तय करता है. इससे यह जानकारी मिलती है कि सीएसएस सिलेक्टर के आधार पर, हर एलिमेंट पर किस तरह की स्टाइल लागू की जाती है. DevTools के computed सेक्शन में यह जानकारी देखी जा सकती है.

कंप्यूटेड स्टाइल
इमेज 3: कंप्यूट की गई स्टाइल जोड़ने के लिए, सीएसएस को पार्स करने वाला मुख्य थ्रेड

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

लेआउट

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

इंसान की फ़ैक्स मशीन का गेम
इमेज 4: पेंटिंग के सामने खड़ा एक व्यक्ति, जिसकी फ़ोन लाइन दूसरे व्यक्ति से जुड़ी हुई है

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

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

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

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

पेंट

ड्रॉइंग गेम
सातवीं इमेज: कैनवस के सामने पेंटब्रश पकड़े हुए एक व्यक्ति. यह सोच रहा है कि पहले गोला बनाना चाहिए या पहले वर्ग बनाना

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

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

z-इंडेक्स विफल
इमेज 8: पेज के एलिमेंट, एचटीएमएल मार्कअप के क्रम में दिख रहे हैं और इमेज को गलत तरीके से रेंडर किया गया है. इसकी वजह यह है कि इसमें z-index को शामिल नहीं किया गया है

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

पेंट के रिकॉर्ड
नौवीं इमेज: लेआउट ट्री से गुज़रता मुख्य थ्रेड, और पेंट रिकॉर्ड बना रहा है

रेंडरिंग पाइपलाइन को अपडेट करना महंगा है

इमेज 10: DOM+ स्टाइल, लेआउट, और पेंट ट्री के जनरेट होने के क्रम में

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

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

गायब फ़्रेम से जेज जैंक
इमेज 11: टाइमलाइन पर ऐनिमेशन फ़्रेम

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

JavaScript से jage जैंक
इमेज 12: टाइमलाइन पर ऐनिमेशन फ़्रेम, लेकिन JavaScript ने एक फ़्रेम को ब्लॉक किया है

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

एनिमेशन फ़्रेम का अनुरोध करें
इमेज 13: ऐनिमेशन फ़्रेम वाली टाइमलाइन पर चल रहे JavaScript के छोटे-छोटे हिस्से

कंपोज़िटिंग

आपको कोई पेज कैसे बनाना चाहिए?

इमेज 14: आसान रास्टरिंग प्रोसेस का ऐनिमेशन

अब ब्राउज़र को दस्तावेज़ की संरचना, हर एलिमेंट की स्टाइल, पेज की ज्यामिति, और पेंट क्रम के बारे में पता है, तो वह पेज कैसे बनाता है? स्क्रीन पर इस जानकारी को पिक्सल में बदलना, रास्टराइज़िंग कहलाता है.

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

कंपोज़िटिंग क्या है

इमेज 15: कंपोज़िटिंग प्रोसेस का ऐनिमेशन

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

लेयर पैनल का इस्तेमाल करके, DevTools में आपकी वेबसाइट को लेयर में बांटने का तरीका देखा जा सकता है.

लेयर में बांटा जा रहा है

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

लेयर ट्री
इमेज 16: मुख्य थ्रेड जो लेआउट ट्री से गुज़रता है और लेयर ट्री बनाता है

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

मुख्य थ्रेड का रास्टर और कंपोज़िट ऑफ़

लेयर ट्री बनाने और पेंट ऑर्डर तय करने के बाद, मुख्य थ्रेड उस जानकारी को कंपोज़िटर थ्रेड को भेज देता है. इसके बाद, कंपोज़िटर थ्रेड हर लेयर को रास्टराइज़ करता है. लेयर, पेज की पूरी लंबाई जितनी बड़ी हो सकती है. इसलिए, कंपोज़िटर थ्रेड उन्हें टाइल में बांटती है और हर टाइल को रास्टर थ्रेड पर भेजती है. रास्टर थ्रेड हर टाइल को रास्टराइज़ करते हैं और उन्हें जीपीयू मेमोरी में स्टोर करते हैं.

रास्टर
इमेज 17: रास्टर थ्रेड से टाइल का बिट मैप बनाया जाता है और जीपीयू को भेजा जाता है

कंपोज़िटर थ्रेड अलग-अलग रास्टर थ्रेड को प्राथमिकता दे सकता है ताकि व्यूपोर्ट (या आस-पास) के अंदर की चीज़ों को पहले रास्टर किया जा सके. 'ज़ूम-इन करें' जैसी चीज़ों को मैनेज करने के लिए, लेयर में अलग-अलग रिज़ॉल्यूशन के लिए कई टाइलिंग होती हैं.

टाइल के रास्टर होने के बाद, कंपोज़िटर थ्रेड कंपोज़िटर फ़्रेम बनाने के लिए, ड्रॉ क्वाड नाम की टाइल की जानकारी इकट्ठा करता है.

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

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

कंपोज़िट
इमेज 18: कंपोज़िटर थ्रेड, जो कंपोज़िटिंग फ़्रेम बना रही है. फ़्रेम को ब्राउज़र प्रोसेस में भेजा जाता है. इसके बाद, जीपीयू पर भेजा जाता है

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

पूरा करें

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

इस सीरीज़ की अगली और आखिरी पोस्ट में, हम कंपोज़िटर थ्रेड पर और ज़्यादा जानकारी देंगे और देखेंगे कि mouse move और click जैसे उपयोगकर्ता इनपुट के आने पर क्या होता है.

क्या आपको पोस्ट पसंद आई? अगर आगे की पोस्ट के लिए आपका कोई सवाल या सुझाव है, तो हमें नीचे टिप्पणी वाले सेक्शन में या Twitter पर @kosamari के ज़रिए आपका जवाब ज़रूर बताएं.

अगला: इनपुट, कंपोज़िटर को आ रहा है