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

फ़्रंटएंड इंटरव्यू: लेआउट थ्रैशिंग के बिना ResizeObserver का उपयोग करें

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

प्रश्न

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

प्रॉम्प्ट और दायरा

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

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

उत्तर में व्यूपोर्ट मीडिया क्वेरीज़ और एलिमेंट ऑब्ज़र्वेशन के बीच अंतर स्पष्ट होना चाहिए और कॉलबैक टाइमिंग, बॉक्स विकल्प, रीड/राइट सेपरेशन, लूप प्रोटेक्शन, बैच्ड अपडेट्स, React Strict Mode, मल्टीपल टारगेट्स, हिडन एलिमेंट्स, SSR और एक्सेसिबिलिटी को कवर किया जाना चाहिए।

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

  • क्या हम content box, border box, या device-pixel content box को ऑब्ज़र्व कर रहे हैं?
  • क्या अपडेट क्लासेस, CSS वेरिएबल्स, Canvas डाइमेंशन्स, या DOM ज्योमेट्री को बदलता है?
  • क्या कॉलबैक ऑब्ज़र्व किए जा रहे एलिमेंट या किसी पूर्वज (ancestor) के साइज़ को बदलेगा?
  • कितने टारगेट्स मौजूद हैं, और क्या अपडेट्स को अगले फ्रेम में संयोजित (coalesce) किया जाना चाहिए?
  • अनमाउंट, हिडन स्टेट और SSR पर ऑब्ज़र्वर क्रिएशन और क्लीनअप को कैसे हैंडल किया जाता है?

30-सेकंड का उत्तर ढांचा

"क्लाइंट पर एक स्टेबल ऑब्ज़र्वर बनाएं और आवश्यक बॉक्स को ऑब्ज़र्व करें। कॉलबैक में, पहले साइज़ कलेक्ट करें, फिर DOM रीड्स को राइट्स से अलग करें। एक बैच्ड फ्रेम में क्लास या CSS वेरिएबल लागू करें ताकि लेआउट बदलना ऑब्ज़र्व किए गए टारगेट में तुरंत फ़ीडबैक न दे सके। अपरिवर्तित मानों को अनदेखा करें; अनमाउंट पर अपडेट्स रोकें, unobserve और disconnect करें। लॉन्ग टास्क, लेआउट काउंट, लूप एरर और Strict Mode रीमाउंट्स का परीक्षण करें।"

चरण-दर-चरण समाधान

ResizeObserver व्यूपोर्ट से स्वतंत्र होकर किसी एलिमेंट के content या border box पर नज़र रखता है। बॉक्स को सोच-समझकर चुनें: लेआउट ब्रेकपॉइंट्स आमतौर पर content या border साइज़ का उपयोग करते हैं, जबकि पिक्सेल-सटीक ड्राइंग device-pixel content का उपयोग कर सकती है। कॉलबैक के अंदर लेआउट-फ़ोर्सिंग प्रॉपर्टीज़ को बार-बार रीड न करें।

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

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

React में, एक स्टेबल ref और कॉलबैक के साथ, केवल क्लाइंट-साइड useLayoutEffect या उपयुक्त इफेक्ट में ऑब्ज़र्वर बनाएं। Strict Mode सेटअप और क्लीनअप को दो बार चला सकता है, इसलिए क्लीनअप इडेम्पोटेंट (idempotent) होना चाहिए। अनमाउंट पर अपडेट्स लागू करना बंद करें, टारगेट्स को unobserve करें और disconnect करें। SSR को window को एक्सेस नहीं करना चाहिए और न ही ऑब्ज़र्वर बनाना चाहिए।

कई कार्ड्स के लिए, एक ऑब्ज़र्वर साझा करें और entry.target को कॉम्पोनेंट स्टेट में मैप करें, लेकिन ओनरशिप को स्पष्ट रखें ताकि एक कार्ड पूरे कॉलबैक को ब्लॉक न कर सके। ड्रैग के दौरान, केवल नवीनतम साइज़ रखें और मनमाना डिबाउंस जोड़ने (जिससे लेआउट लैग होता है) के बजाय एक एनिमेशन फ्रेम में अपडेट्स को मर्ज करें।

हिडन एलिमेंट्स, display:none, फ़ॉन्ट लोडिंग और स्क्रॉलबार साइज़ बदल सकते हैं। शुरुआती ज़ीरो-साइज़ एंट्री के लिए एक उपयोगी डिफ़ॉल्ट प्रदान करें और पहले वैध मेज़रमेंट के बाद स्विच करें। विशुद्ध स्टाइल ब्रेकपॉइंट्स के लिए CSS कंटेनर क्वेरीज़ को प्राथमिकता दें; जब जावास्क्रिप्ट को Canvas, थर्ड-पार्टी विजेट्स या बिज़नेस कैलकुलेशंस को ड्राइव करना हो तब ResizeObserver का उपयोग करें।

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

मॉडल उच्च-गुणवत्ता वाला उत्तर

"मैं क्लाइंट-साइड पर एक स्टेबल ResizeObserver बनाता हूँ और सोच-समझकर content या border box चुनता हूँ। कॉलबैक नवीनतम एंट्रीज़ को रिकॉर्ड करता है और ब्रेकपॉइंट्स की गणना करता है; यह लेआउट को बार-बार रीड और राइट नहीं करता है। मैं एक बैच्ड फ्रेम में CSS वेरिएबल्स या क्लासेस लागू करता हूँ। यदि कोई राइट ऑब्ज़र्व किए गए साइज़ को बदलता है, तो मैं फ़ीडबैक लूप को रोकने के लिए हिस्टैरिसीस, कंस्ट्रेंट्स और कन्वर्जेंस चेक जोड़ता हूँ।

React क्लीनअप इडेम्पोटेंट है: अनमाउंट पर अपडेट्स रोकें, unobserve करें और disconnect करें। कई कार्ड टारगेट-आधारित डिस्पैच के साथ एक ऑब्ज़र्वर साझा कर सकते हैं। मैं ड्रैग रीसाइज़, फ़ॉन्ट लोडिंग, हिडन और दिखाए गए स्टेट्स, और Strict Mode रीमाउंट्स का परीक्षण करता हूँ, लेआउट्स, लॉन्ग टास्क, लूप एरर्स, डुप्लिकेट सब्सक्रिप्शन्स और एक्सेसिबल इंटरैक्शन को मापता हूँ।"

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

  • ResizeObserver को व्यूपोर्ट मीडिया क्वेरी की तरह मानना → कॉम्पोनेंट्स विभिन्न कंटेनरों में विफल हो जाते हैं → स्वयं एलिमेंट को ऑब्ज़र्व करें।
  • कॉलबैक में बहुत सारे DOM को रीड और राइट करना → फ़ोर्स्ड लेआउट और थ्रैशिंग → रीड्स को बैच करें और अगले फ्रेम पर राइट करें।
  • कन्वर्जेंस के बिना ऑब्ज़र्व किए गए टारगेट को बदलना → फ़ीडबैक लूप → हिस्टैरिसीस, कंस्ट्रेंट्स और डिटेक्शन का उपयोग करें।
  • प्रत्येक रेंडर पर एक ऑब्ज़र्वर बनाना → डुप्लिकेट कॉलबैक्स और लीक्स → स्टेबल refs, डिपेंडेंसीज़ और क्लीनअप।
  • केवल unobserve करना लेकिन कॉलबैक स्टेट बनाए रखना → अनमाउंट के बाद भी अपडेट्स जारी रहते हैं → इनएक्टिव मार्क करें, unobserve और disconnect करें।
  • ज़ीरो साइज़ पर सबसे बड़ा लेआउट लागू करना → पहला पेंट जंप करता है → एक वैध एंट्री मिलने तक डिफ़ॉल्ट स्टेट का उपयोग करें।
  • प्रत्येक ब्रेकपॉइंट के लिए जावास्क्रिप्ट का उपयोग करना → अनावश्यक जटिलता → जब CSS पर्याप्त हो तो कंटेनर क्वेरीज़ का उपयोग करें।
  • केवल सामान्य ड्रैगिंग का परीक्षण करना → फ़ॉन्ट, हिडन और Strict Mode की समस्याएँ छूट जाती हैं → लाइफसाइकल और रिसोर्स परिवर्तनों को कवर करें।

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

फ़ॉलो-अप 1: कॉलबैक कब चलता है?

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

फ़ॉलो-अप 2: window.resize का उपयोग क्यों नहीं करते?

यह व्यूपोर्ट के परिवर्तनों को दर्शाता है, न कि ग्रिड, साइडबार या फ़ॉन्ट के कारण बदलने वाले कार्ड को। ResizeObserver सीधे एलिमेंट को ऑब्ज़र्व करता है।

फ़ॉलो-अप 3: आप रीड्स और राइट्स को कैसे अलग करते हैं?

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

फ़ॉलो-अप 4: प्रति एलिमेंट एक ऑब्ज़र्वर या एक शेयर्ड ऑब्ज़र्वर?

स्वतंत्र रूप से प्रबंधित कुछ एलिमेंट्स अलग-अलग ऑब्ज़र्वर का उपयोग कर सकते हैं। कई टारगेट्स एक को साझा कर सकते हैं और टारगेट के अनुसार डिस्पैच कर सकते हैं, जब तक कि कॉलबैक का कार्य सीमित रहे।

फ़ॉलो-अप 5: display:none के बाद क्या होता है?

ज़ीरो साइज़ को अस्थायी मानें, दिखने के बाद एक वैध एंट्री की प्रतीक्षा करें, और छिपे होने के दौरान राइट लूप से बचें। ज़ीरो को स्थायी ब्रेकपॉइंट न मानें।

फ़ॉलो-अप 6: React Strict Mode बग्स को क्यों उजागर करता है?

डेवलपमेंट मोड असममित साइड इफेक्ट्स को उजागर करने के लिए इफेक्ट सेटअप और क्लीनअप को दो बार चला सकता है। क्लीनअप दोबारा चलने योग्य (repeatable) होना चाहिए और पीछे कोई ऑब्ज़र्वर या अपडेट कॉलबैक नहीं छोड़ना चाहिए।

फ़ॉलो-अप 7: CSS कंटेनर क्वेरीज़ को कब प्राथमिकता मिलनी चाहिए?

विशुद्ध कंटेनर ब्रेकपॉइंट्स के लिए CSS का उपयोग करें। जब साइज़ को Canvas, थर्ड-पार्टी API, जटिल मेज़रमेंट या बिज़नेस कैलकुलेशंस को ड्राइव करना हो तब ResizeObserver का उपयोग करें।

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

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