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

मैरिको कोसाका

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

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

ब्राउज़र के हिसाब से इवेंट डालें

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

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

इनपुट इवेंट
इमेज 1: इनपुट इवेंट, ब्राउज़र प्रोसेस से होकर रेंडर करने की प्रोसेस में रूट किया गया

कंपोज़िटर को इनपुट इवेंट मिलते हैं

इमेज 2: पेज लेयर पर कर्सर घुमाना

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

उन इलाकों के बारे में समझना जहां तेज़ी से स्क्रोल नहीं किया जा सकता

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

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

इवेंट हैंडलर लिखते समय ध्यान रखें

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

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault();
    }
});

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

पूरा पेज तेज़ स्क्रोल न किया जा सकने वाला क्षेत्र
इमेज 4: ब्यौरे में दिए गए इनपुट का डायग्राम, जिसमें उस इलाके के बारे में बताया गया है जिसे तेज़ी से स्क्रोल नहीं किया जा सकता और पूरा पेज कवर किया गया है

इसे कम करने के लिए, इवेंट सूची में शामिल passive: true विकल्प को पास किया जा सकता है. इससे ब्राउज़र को यह संकेत मिलता है कि आप अब भी मुख्य थ्रेड में इवेंट सुनना चाहते हैं, लेकिन कंपोज़िटर नए फ़्रेम को कंपोज़िट भी कर सकता है.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

देखें कि इवेंट को रद्द किया जा सकता है या नहीं

पेज स्क्रोल
इमेज 5: एक वेब पेज, जिसका कुछ हिस्सा हॉरिज़ॉन्टल स्क्रोल पर फ़ोकस किया गया है

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

पॉइंटर इवेंट में passive: true विकल्प का इस्तेमाल करने का मतलब है कि पेज स्क्रोल करना आसान हो सकता है. हालांकि, हो सकता है कि स्क्रोल की दिशा को सीमित करने के लिए, preventDefault की मदद से वर्टिकल स्क्रोल करना शुरू हो गया हो. event.cancelable तरीके का इस्तेमाल करके यह पता लगाया जा सकता है कि आपने यह सुविधा बंद कर दी है या नहीं.

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

इसके अलावा, इवेंट हैंडलर को पूरी तरह से हटाने के लिए, touch-action जैसे सीएसएस नियम का इस्तेमाल किया जा सकता है.

#area {
  touch-action: pan-x;
}

इवेंट के लिए टारगेट खोजना

हिट टेस्ट
इमेज 6: पेंट के रिकॉर्ड पर नज़र डालने वाला मुख्य धागा, जो पूछता है कि x.y पॉइंट पर क्या बनाया गया है

जब कंपोज़िटर थ्रेड मुख्य थ्रेड को इनपुट इवेंट भेजता है, तो इवेंट टारगेट को ढूंढने के लिए सबसे पहले हिट टेस्ट चलाया जाता है. हिट टेस्ट, पेंट रिकॉर्ड के डेटा का इस्तेमाल करता है. यह डेटा रेंडरिंग प्रोसेस में जनरेट होता है. इससे यह पता चलता है कि इवेंट वाले पॉइंट कोऑर्डिनेट के नीचे क्या है.

मुख्य थ्रेड से इवेंट की जानकारी भेजने की संख्या को कम करना

पिछले पोस्ट में, हमने बताया था कि हमारा सामान्य डिसप्ले एक सेकंड में 60 बार स्क्रीन को कैसे रीफ़्रेश करता है और याद रखने के लिए हम किस तरह स्मूद ऐनिमेशन का इस्तेमाल कर सकते हैं. इनपुट के लिए, एक सामान्य टच-स्क्रीन डिवाइस एक सेकंड में 60 से 120 बार टच इवेंट डिलीवर करता है और सामान्य माउस एक सेकंड में 100 बार इवेंट डिलीवर करता है. इनपुट इवेंट की क्वालिटी, हमारी स्क्रीन रीफ़्रेश किए जा सकने से ज़्यादा है.

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

फ़िल्टर नहीं किए गए इवेंट
इमेज 7: इवेंट की वजह से फ़्रेम टाइमलाइन पर ट्रैफ़िक आ रहा है, जिसकी वजह से पेज जैंक हो सकता है

मुख्य थ्रेड पर बहुत ज़्यादा कॉल को कम करने के लिए, Chrome लगातार होने वाले इवेंट (जैसे कि wheel, mousewheel, mousemove, pointermove, touchmove) को इकट्ठा करता है और अगले requestAnimationFrame से ठीक पहले होने तक देर करता है.

इकट्ठा किए गए इवेंट
इमेज 8: टाइमलाइन पहले की तरह ही है, लेकिन इवेंट तैयार हो रहा है और इसमें देरी हो रही है

keydown, keyup, mouseup, mousedown, touchstart, और touchend जैसे अलग-अलग इवेंट को तुरंत भेज दिया जाता है.

इंट्रा-फ़्रेम इवेंट पाने के लिए, getCoalescedEvents का इस्तेमाल करें

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

getCoalescedEvents
इमेज 9: बाईं ओर स्मूद टच जेस्चर पाथ, दाईं ओर सीमित पाथ को जोड़ा गया
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});

अगले चरण

इस सीरीज़ में, हमने वेब ब्राउज़र की अंदरूनी गतिविधियों के बारे में बताया है. अगर आपने कभी यह नहीं सोचा है कि DevTools आपको इवेंट हैंडलर में {passive: true} जोड़ने का सुझाव क्यों देता है या अपने स्क्रिप्ट टैग में async एट्रिब्यूट क्यों लिखा जा सकता है, तो मुझे उम्मीद है कि यह सीरीज़ इस बारे में आपको कुछ बताएगी कि तेज़ और बेहतर वेब अनुभव देने के लिए ब्राउज़र को उन जानकारी की ज़रूरत क्यों है.

लाइटहाउस का इस्तेमाल करें

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

परफ़ॉर्मेंस को मापने का तरीका जानें

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

अपनी साइट में सुविधा की नीति जोड़ना

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

आखिर में खास जानकारी

धन्यवाद

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

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

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