प्रतिनिधि इंटरव्यू विषय

फ्रंटएंड इंटरव्यू: लेआउट थ्रैशिंग (Layout Thrashing) का निदान और समाधान कैसे करें?

फ्रंटएंडकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

300 कार्ड्स वाला एक डैशबोर्ड स्क्रॉलिंग और रिसाइजिंग के दौरान जर्की (अटक-अटक कर चलने वाला) हो जाता है। इसका हैंडलर प्रत्येक कार्ड की ज्योमेट्री को पढ़ता है (read), स्टाइल्स लिखता है (write), और फिर से ज्योमेट्री पढ़ता है; एक परफॉरमेंस ट्रेस बार-बार होने वाले Layout इवेंट्स और फोर्स्ड-रिफ्लो (forced-reflow) चेतावनियां दिखाता है। आप इसके कारण को कैसे साबित करेंगे, माप को तोड़े बिना कोड को कैसे रीफैक्टर करेंगे, और परिणाम को कैसे सत्यापित करेंगे?

प्रॉम्प्ट और लागू संदर्भ

एक डैशबोर्ड 300 कार्ड्स रेंडर करता है। स्क्रॉलिंग और रिसाइजिंग के दौरान, एक हैंडलर प्रत्येक कार्ड के बाउंडिंग बॉक्स को पढ़ता है, उसकी चौड़ाई और स्थिति बदलता है, और फिर उसकी ऊंचाई पढ़ता है। इंटरफ़ेस जर्की हो जाता है। क्रोम परफॉरमेंस रिकॉर्डिंग हैंडलर के अंदर बार-बार पर्पल Layout इवेंट्स और फोर्स्ड-रिफ्लो चेतावनियां दिखाती है।

ब्राउज़र की JavaScript → style → layout → paint → composite पाइपलाइन की व्याख्या करें, साबित करें कि क्या यह कोड लेआउट थ्रैशिंग का कारण बन रहा है, बासी (stale) ज्योमेट्री का उपयोग किए बिना इसे रीफैक्टर करें, और एक सत्यापन योजना परिभाषित करें। कार्ड्स की संख्या और ट्रेस के लक्षण इंटरव्यू की धारणाएं हैं, किसी वास्तविक उत्पाद के अवलोकन नहीं।

यह एक फ्रंटएंड परफॉरमेंस डायग्नोसिस का प्रश्न है। मुख्य कौशल अमान्यकरण (invalidation) और सिंक्रोनस ज्योमेट्री रीड्स को ट्रेस साक्ष्य और एक सुरक्षित कोड परिवर्तन से जोड़ना है। यह Core Web Vitals जांच की तुलना में अधिक संकीर्ण है, जो फील्ड मेट्रिक्स से शुरू होती है, और एक नए URL नेविगेशन को ट्रेस करने से अलग है, जो नेटवर्क और प्रारंभिक रेंडरिंग चरणों को कवर करता है।

इंटरव्यूअर क्या मूल्यांकन करता है

पहला, क्या उम्मीदवार अमान्यकरण (invalidation) और निष्पादन (execution) के बीच अंतर कर सकता है? एक DOM या स्टाइल राइट, ज्योमेट्री की तुरंत पुनर्गणना किए बिना स्टाइल या लेआउट को "डर्टी" (dirty) के रूप में चिह्नित कर सकता है। बाद में कॉल किया गया एक API, जिसे वर्तमान ज्योमेट्री लौटाना आवश्यक है, ब्राउज़र को लंबित स्टाइल और लेआउट को सिंक्रोनस रूप से फ्लश करने के लिए मजबूर कर सकता है।

दूसरा, क्या उम्मीदवार थ्रैशिंग को "धीमी प्रॉपर्टीज़" की सूची के बजाय एक निर्भरता पैटर्न (dependency pattern) के रूप में समझा सकता है? एक राइट के बाद एक आवश्यक रीड वैध हो सकता है। नुकसानदेह पैटर्न कई तत्वों या फ्रेम्स में बार-बार राइट → लेआउट-निर्भर रीड → राइट करना है, जो ब्राउज़र को कार्य को संयोजित (coalesce) करने से रोकता है।

तीसरा, क्या उम्मीदवार ऑप्टिमाइज़ करने से पहले निदान कर सकता है? एक मजबूत उत्तर वास्तविक इंटरैक्शन को रिकॉर्ड करता है, Layout इवेंट्स के लिए आरंभकर्ताओं (initiators) और कॉल स्टैक्स की जांच करता है, स्क्रिप्टिंग, स्टाइल, लेआउट और पेंट में बिताए गए समय की तुलना करता है, और पुष्टि करता है कि संदिग्ध हैंडलर कारण पथ (causal path) पर है। केवल पर्पल बार्स यह साबित नहीं करते हैं कि हर लेआउट से बचा जा सकता है।

चौथा, क्या उम्मीदवार शुद्धता (correctness) को बनाए रख सकता है? सभी रीड्स को शुरुआत में ले जाना केवल तभी काम करता है जब वे माप उस स्थिति का वर्णन करते हैं जिसकी एल्गोरिदम को आवश्यकता है। यदि प्रत्येक राइट जानबूझकर अगले माप को बदलता है, तो एल्गोरिदम या डेटा मॉडल को बदलना होगा; ज्योमेट्री को आंख मूंदकर कैश करने से एक तेज़ लेकिन गलत लेआउट बनता है।

अंत में, क्या उम्मीदवार वास्तविक निर्भरता के आधार पर बैचिंग, requestAnimationFrame, ऑब्जर्वर्स, CSS लेआउट, कंटेनमेंट, और कंपोजिटर-अनुकूल प्रॉपर्टीज़ के बीच चयन कर सकता है? requestAnimationFrame केवल समय बदलता है लेकिन महंगे कार्य को मुफ़्त नहीं बनाता है, और will-change लेआउट के लिए कोई सामान्य समाधान नहीं है।

उत्तर देने से पहले स्पष्ट करने योग्य प्रश्न

  • कौन सा इंटरैक्शन धीमा है? स्क्रॉल, रिसाइज, प्रारंभिक रेंडर, ड्रैग और एक बार का विस्तार (expansion) के अलग-अलग बजट और शेड्यूलिंग विकल्प होते हैं। बेसलाइन निरंतर स्क्रॉल और रिसाइज है।
  • कौन से रीड्स और राइट्स होते हैं? ज्योमेट्री रीड्स में getBoundingClientRect(), offsetWidth, और offsetHeight शामिल हैं; राइट्स क्लासेस, इनलाइन स्टाइल्स, कंटेंट या DOM संरचना को बदल सकते हैं। केवल API नामों की तुलना में सटीक क्रम अधिक मायने रखता है।
  • क्या एक कार्ड का नया आकार दूसरे कार्ड के माप को निर्धारित करता है? यदि नहीं, तो सभी माप आमतौर पर एक स्थिर स्थिति से पढ़े जा सकते हैं। यदि हाँ, तो एल्गोरिदम में एक क्रमिक निर्भरता (sequential dependency) है जिसे साधारण बैचिंग द्वारा सुरक्षित नहीं रखा जा सकता है।
  • क्या CSS लेआउट को संभाल सकता है? ग्रिड, फ्लेक्सबॉक्स, कंटेनर क्वेरीज़ और आंतरिक आकार निर्धारण (intrinsic sizing) जावास्क्रिप्ट माप को पूरी तरह से समाप्त कर सकते हैं। यह अक्सर एक माप लूप को ऑप्टिमाइज़ करने से अधिक प्रभावी होता है।
  • क्या इनपुट कहीं और म्यूटेट हो रहा है? फ्रेमवर्क कमिट, छवियां, फ़ॉन्ट्स, थर्ड-पार्टी विजेट्स या ऑब्जर्वर्स चरणों के बीच लेआउट को अमान्य कर सकते हैं। समाधान के लिए एक स्वामी या एक स्पष्ट शेड्यूलिंग प्रोटोकॉल की आवश्यकता होती है।
  • दृष्टिगत रूप से क्या समान रहना चाहिए? कार्यान्वयन को बदलने से पहले कार्ड की स्थिति, आकार, फ़ोकस व्यवहार, स्क्रॉल एंकरिंग और रिसाइज प्रतिक्रिया को परिभाषित करें।
  • लक्षित वातावरण (target environment) क्या है? प्रभावित व्यूपोर्ट और डिवाइस वर्ग पर पुनरुत्पादन करें। एक तेज़ डेवलपमेंट लैपटॉप बार-बार होने वाले लेआउट्स को छिपा सकता है जो सीमित CPU पर विफल हो जाते हैं।

30-सेकंड उत्तर फ्रेमवर्क

"मैं सबसे पहले सटीक स्क्रॉल या रिसाइज इंटरैक्शन को रिकॉर्ड करूंगा और उनके आरंभकर्ता और कॉल स्टैक को खोजने के लिए बार-बार होने वाले Layout इवेंट्स का चयन करूंगा। एक स्टाइल राइट ज्योमेट्री को अमान्य कर देता है; इसके बाद आने वाले getBoundingClientRect() या offsetHeight को वर्तमान मान लौटाना होगा, इसलिए ब्राउज़र स्टाइल और लेआउट को सिंक्रोनस रूप से फ्लश कर सकता है। 300 कार्ड्स के लिए उस क्रम को दोहराना ही लेआउट थ्रैशिंग है। यदि प्रत्येक कार्ड समान प्री-अपडेट स्थिति का उपयोग कर सकता है, तो मैं पहले सभी आवश्यक ज्योमेट्री को पढ़ूंगा, मेमोरी में गणना करूंगा, फिर अगले विज़ुअल अपडेट में एक साथ राइट्स निष्पादित करूंगा। जब जावास्क्रिप्ट पोलिंग अनावश्यक हो, तो मैं CSS लेआउट या ऑब्जर्वर को प्राथमिकता दूंगा। फिर मैं उसी नियतात्मक इंटरैक्शन को दोबारा चलाऊंगा और लेआउट संख्या, लेआउट अवधि, फ्रेम अंतराल और विज़ुअल शुद्धता की तुलना करूंगा। मैं यह दावा नहीं करूंगा कि केवल requestAnimationFrame दोहराए गए कार्य को ठीक कर देता है।"

चरण-दर-चरण गहन विश्लेषण

चरण 1: कारण मॉडल (causal model) का निर्माण करें

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

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

उपयोगी नियम है: एक ज्ञात विज़ुअल स्थिति से पढ़ें, DOM को छुए बिना गणना करें, फिर अगली स्थिति को एक साथ लिखें। यह एक निर्भरता नियम है, यह वादा नहीं कि प्रत्येक रीड या राइट महंगा है।

चरण 2: साबित करें कि हैंडलर ही जिम्मेदार है

एक नियतात्मक क्रिया के इर्द-गिर्द परफॉरमेंस रिकॉर्डिंग कैप्चर करें: समान कार्ड डेटा, व्यूपोर्ट, स्क्रॉल दूरी या रिसाइज क्रम, और CPU स्थितियां। Frames और Main ट्रैक्स का निरीक्षण करें। लंबे Layout इवेंट्स का चयन करें और "initiated by" या स्टैक का अनुसरण करते हुए एप्लिकेशन कोड तक पहुँचें। जांचें कि एक हैंडलर के अंदर कितने लेआउट इवेंट होते हैं और वे कितना समय लेते हैं।

यदि ट्रेस बहुत घना है, तो हैंडलर के आसपास अस्थायी परफॉरमेंस मार्क्स जोड़ें। पेंट फ्लैशिंग और लेयर बॉर्डर्स का उपयोग केवल सहायक साक्ष्य के रूप में करें: वे पुनः पेंट किए गए क्षेत्रों और लेयर्स को प्रकट करते हैं, जबकि परफॉरमेंस ट्रेस फोर्स्ड लेआउट को कोड से जोड़ता है। स्क्रिप्टिंग और पेंट समय भी रिकॉर्ड करें; लेआउट को हटाना ऐसे हैंडलर को ठीक नहीं करेगा जो असंबंधित गणना या बहुत बड़े रीपेंट से प्रभावित है।

एक नियंत्रण (control) बनाएं। डेटा और इंटरैक्शन को अक्षुण्ण रखते हुए केवल संदिग्ध रीड-राइट लूप को अक्षम करें। यदि बार-बार होने वाले Layout इवेंट्स और फ्रेम गैप्स गायब हो जाते हैं, तो कारण का दावा मजबूत हो जाता है। यदि वे बने रहते हैं, तो पसंदीदा निदान को जबरन लागू करने के बजाय फ्रेमवर्क कमिट्स, इमेज साइज़िंग, फ़ॉन्ट्स और थर्ड-पार्टी कोड का निरीक्षण करें।

चरण 3: स्वतंत्र मापों को चरणों (phases) में रीफैक्टर करें

मान लीजिए कि मूल हैंडलर रीड्स और राइट्स को बारी-बारी से करता है:

js
function positionCards(container, cards, columns) {
  let top = 0;

  for (const card of cards) {
    const width = container.getBoundingClientRect().width / columns;
    card.style.width = `${Math.floor(width)}px`;
    const height = card.offsetHeight;
    card.style.transform = `translateY(${top}px)`;
    top += height;
  }
}

यहाँ, प्रत्येक ऊंचाई वास्तव में नई चौड़ाई पर निर्भर करती है, इसलिए हर पुरानी ऊंचाई को कैश करना गलत होगा। कोड को 300 बारी-बारी वाले चरणों के बजाय दो स्थिर विज़ुअल स्थितियों में विभाजित करें:

js
function positionCards(container, cards, columns) {
  const width = Math.floor(container.getBoundingClientRect().width / columns);

  for (const card of cards) {
    card.style.width = `${width}px`;
  }

  requestAnimationFrame(() => {
    const heights = cards.map((card) => card.offsetHeight);
    let top = 0;

    cards.forEach((card, index) => {
      card.style.transform = `translateY(${top}px)`;
      top += heights[index];
    });
  });
}

पहला रीड चौड़ाई-पूर्व कंटेनर का अवलोकन करता है। सभी चौड़ाई राइट्स समूहीकृत हैं। पहली ऊंचाई का रीड नई चौड़ाई के लिए एक आवश्यक लेआउट की मांग कर सकता है, जबकि शेष ऊंचाई रीड्स उस स्थिर चौड़ाई-पश्चात की ज्योमेट्री का पुन: उपयोग करते हैं; ट्रांसफ़ॉर्म्स को फिर किसी अन्य ज्योमेट्री रीड के बिना लिखा जाता है। एनिमेशन-फ्रेम कॉलबैक दूसरे चरण का समन्वय करता है, लेकिन सुधार सैकड़ों बारी-बारी वाली निर्भरताओं को दो स्पष्ट स्थितियों में कम करने से आता है, न कि कॉलबैक नाम से।

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

चरण 4: वास्तविक क्रमिक निर्भरताओं (genuine sequential dependencies) को संभालें

बैचिंग तब अमान्य होती है जब कार्ड A को राइट करने से जानबूझकर वह ज्योमेट्री बदल जाती है जिसे कार्ड B के लिए पढ़ा जाना चाहिए। सभी मापों को स्वतंत्र मानने का दिखावा करने के बजाय उस बाधा को स्पष्ट करें। संभावित सुधारों में एक संचयी (cumulative) इन-मेमोरी मॉडल से प्रत्येक स्थिति प्राप्त करना, CSS ग्रिड या फ्लेक्सबॉक्स को फ्लो लेआउट करने देना, प्रत्येक चाइल्ड के बजाय एक कंटेनर को मापना, या प्रभाव को फिर से डिज़ाइन करना शामिल है ताकि उसे केवल पिछले कमिट किए गए फ्रेम की आवश्यकता हो।

जब कंटेंट का आकार एसिंक्रोनस रूप से बदलता है, तो ResizeObserver हर स्क्रॉल इवेंट को पोल किए बिना आकार परिवर्तनों की रिपोर्ट कर सकता है। इसके कॉलबैक को अभी भी रिसाइज फीडबैक लूप बनाने से बचना चाहिए: वितरित अवलोकनों से गणना करें, राइट्स को बैच करें, और अभिसरण नियम (convergence rule) के बिना एक ही देखे गए बॉक्स का बार-बार आकार न बदलें।

CSS कंटेनमेंट उस सीमा को कम कर सकता है जहाँ तक लेआउट या पेंट अमान्यकरण फैलता है जब घटक सीमा वास्तव में स्वतंत्र होती है। यह आंतरिक आकार, ओवरफ़्लो और कंटेनिंग-ब्लॉक व्यवहार को भी बदल सकता है, इसलिए रूप-रंग और पहुंच क्षमता (accessibility) को सत्यापित करें। एक छोटा अमान्यकरण दायरा लागत कम करता है; यह बार-बार मजबूर किए गए लेआउट को सही नहीं ठहराता।

चरण 5: सस्ते विज़ुअल परिवर्तन केवल तभी चुनें जब सिमेंटिक्स अनुमति दें

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

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

चरण 6: परफॉरमेंस और शुद्धता को एक साथ सत्यापित करें

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

कार्ड बाउंड्स, रैपिंग, फ़ोकस क्रम, पॉइंटर लक्ष्य, स्क्रॉल स्थिति, ज़ूम, डायनामिक फ़ॉन्ट्स और छवियां, और कई व्यूपोर्ट आकारों को मान्य करें। प्रारंभिक रेंडर के बाद तेज़ इवेंट बर्स्ट्स और सामग्री परिवर्तनों का परीक्षण करें। कम लेआउट वाला ट्रेस पास नहीं माना जाएगा यदि कार्ड्स ओवरलैप होते हैं या कीबोर्ड फ़ोकस कूदता है।

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

उच्च गुणवत्ता वाला नमूना उत्तर

"मैं समान 300 कार्ड्स के साथ एक निश्चित रिसाइज क्रम को पुनरुत्पादित करूंगा और इसे Performance पैनल में रिकॉर्ड करूंगा। मैं बार-बार होने वाले Layout इवेंट्स का चयन करूंगा, उनके आरंभकर्ताओं का अनुसरण करूंगा, और पुष्टि करूंगा कि हैंडलर ज्योमेट्री लिखता है और फिर ब्राउज़र द्वारा परिवर्तनों को संयोजित करने से पहले getBoundingClientRect() या offsetHeight को कॉल करता है। यह वह कारण पैटर्न है जिसे मैं लेआउट थ्रैशिंग कहूंगा; केवल पर्पल श्रेणी अपने आप में पर्याप्त नहीं है।

फिर मैं जांचूंगा कि क्या प्रत्येक कार्ड की गणना प्री-अपडेट लेआउट से की जा सकती है। यदि ऐसा है, तो मैं पहले सभी बॉक्स को पढ़ूंगा, प्लेन डेटा में अगले स्टाइल्स की गणना करूंगा, और राइट्स को एक साथ निष्पादित करूंगा। मैं रिसाइज और स्क्रॉल सूचनाओं को एक लंबित विज़ुअल अपडेट में संयोजित करूंगा। requestAnimationFrame उस अपडेट को रखने में मदद करता है, लेकिन यह अपने आप में इंटरलीव्ड रीड्स और राइट्स को ठीक नहीं करता है। यदि माप केवल सामान्य प्रवाह की भरपाई कर रहे हैं, तो मैं CSS ग्रिड को प्राथमिकता दूंगा। यदि रेंडर के बाद आकार स्वतंत्र रूप से बदलते हैं, तो मैं ResizeObserver पर विचार करूंगा और फीडबैक लूप्स से रक्षा करूंगा।

यदि कार्ड B वास्तव में कार्ड A के पोस्ट-राइट आकार पर निर्भर करता है, तो मैं पुराने मान को कैश करके यह नहीं कहूंगा कि यह ठीक हो गया है। मैं एक संचयी मॉडल से स्थितियां प्राप्त करूंगा या लेआउट इंजन को निर्भरता संभालने दूंगा। मैं ट्रांसफ़ॉर्म्स का उपयोग केवल उस मूवमेंट के लिए करूंगा जिसे डॉक्यूमेंट फ्लो को प्रभावित करने की आवश्यकता नहीं है।

अंत में, मैं उसी रिकॉर्डिंग को दोहराऊंगा और लेआउट संख्या और अवधि, फोर्स्ड-रिफ्लो स्टैक्स, फ्रेम गैप्स, स्क्रिप्टिंग और पेंट की तुलना करूंगा। मैं बाउंड्स, रैपिंग, फ़ोकस, स्क्रॉल एंकरिंग, ज़ूम और देर से लोड होने वाली सामग्री को भी सत्यापित करूंगा। सफलता का अर्थ है कि बार-बार होने वाले फोर्स्ड लेआउट बासी मापों या नए पेंट बॉटलनेक के बिना गायब हो जाएं या काफी कम हो जाएं।"

सामान्य गलतियाँ

  • प्रत्येक लेआउट इवेंट को थ्रैशिंग कहना → जब भी ज्योमेट्री बदलती है तो लेआउट आवश्यक होता है → बारी-बारी वाली निर्भरता के कारण बार-बार होने वाले सिंक्रोनस फ्लश को दिखाएं।
  • मूल लूप के चारों ओर केवल requestAnimationFrame जोड़ना → एक ही कॉलबैक के अंदर समान रीड्स और राइट्स अभी भी बारी-बारी से चलते हैं → पहले रीड, गणना और राइट चरणों को अलग करें।
  • प्रत्येक माप को हमेशा के लिए कैश करना → फ़ॉन्ट्स, कंटेंट, ज़ूम और व्यूपोर्ट परिवर्तन ज्योमेट्री को बासी बना देते हैं → अमान्यकरण इनपुट परिभाषित करें या उपयुक्त ऑब्जर्वर का उपयोग करें।
  • समाधान के रूप में will-change का उपयोग करना → लेयर संकेत ज्योमेट्री निर्भरता को नहीं हटाते हैं और संसाधनों की खपत करते हैं → डेटा प्रवाह को ठीक करें, फिर केवल उचित विज़ुअल प्रभावों को प्रमोट करें।
  • चौड़ाई को आंख मूंदकर ट्रांसफ़ॉर्म स्केल से बदलना → डॉक्यूमेंट फ्लो, टेक्स्ट, हिट टेस्टिंग या विज़ुअल गुणवत्ता गलत हो सकती है → कंपोजिटर-अनुकूल परिवर्तनों का उपयोग केवल तभी करें जब सिमेंटिक्स अनुमति दें।
  • ट्रेस के बिना ऑप्टिमाइज़ करना → महंगा काम कहीं और स्क्रिप्टिंग या पेंट हो सकता है → इंटरैक्शन को कैप्चर करें और इवेंट आरंभकर्ताओं को कोड तक ट्रैक करें।
  • केवल औसत FPS की जांच करना → औसत लंबे फ्रेम्स को छुपाते हैं और कारण की पहचान नहीं करते हैं → समान वर्कलोड के लिए लेआउट संख्या, अवधि, स्टैक्स और फ्रेम अंतराल की तुलना करें।
  • विज़ुअल शुद्धता की अनदेखी करना → बासी ज्योमेट्री ट्रेस को तेज़ दिखा सकती है → रीफैक्टरिंग के बाद लेआउट, फ़ोकस, स्क्रॉलिंग, ज़ूम और एसिंक्रोनस कंटेंट का परीक्षण करें।

फॉलो-अप प्रश्न और उत्तर

फॉलो-अप 1: क्या requestAnimationFrame फोर्स्ड सिंक्रोनस लेआउट को रोकता है?

नहीं। यह भविष्य के पेंट से पहले एक कॉलबैक शेड्यूल करता है। यदि वह कॉलबैक ज्योमेट्री राइट्स और लेआउट-निर्भर रीड्स को बारी-बारी से निष्पादित करता है, तो यह अभी भी बार-बार सिंक्रोनस लेआउट को बाध्य कर सकता है और फ्रेम में देरी कर सकता है। निर्भरता क्रम को ठीक करने के बाद बैच राइट या एनिमेशन चरण को समन्वित करने के लिए इसका उपयोग करें।

फॉलो-अप 2: एक फोर्स्ड लेआउट कब स्वीकार्य है?

जब वर्तमान ज्योमेट्री की वास्तव में आवश्यकता हो और कार्य सीमित (bounded) हो—उदाहरण के लिए, स्थिति निर्धारित करने से पहले एक नए खुले पॉपओवर को एक बार मापना। आवश्यक मानों को एक साथ पढ़ें, लूप में बार-बार फ्लश करने से बचें, और प्रतिनिधि उपकरणों पर लागत को सत्यापित करें। "फोर्स्ड" शेड्यूलिंग का वर्णन करता है, यह स्वतः कोई बग नहीं है।

फॉलो-अप 3: क्या ResizeObserver लेआउट कार्य को समाप्त कर देगा?

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

फॉलो-अप 4: क्या होगा यदि लेआउट की संख्या कम हो जाती है लेकिन एनीमेशन धीमा रहता है?

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

फॉलो-अप 5: आप किसी कंपोनेंट फ्रेमवर्क में इसका परीक्षण कैसे करेंगे?

ट्रेस में फ्रेमवर्क कमिट और मापन प्रभाव (measurement effect) को चिह्नित करें, फिर निर्धारित करें कि क्या एप्लिकेशन कोड फ्रेमवर्क DOM राइट्स के बाद रीड करता है। शुद्धता के लिए आवश्यक लाइफसाइकिल चरण में मापन रखें, लेकिन इसे सीमित और चरण-पृथक बनाएं। प्रोडक्शन लागत को सीधे फ्रेमवर्क पर मढ़ने से पहले बार-बार माउंट्स, स्टेट अपडेट्स, लेट कंटेंट और डेवलपमेंट-मोड आर्टिफ़ैक्ट्स का परीक्षण करें।

सार्वजनिक स्रोत

संबंधित प्रश्न