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

Frontend Interview: Navigation API के साथ आप Recoverable SPA Navigation कैसे डिज़ाइन करेंगे?

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

प्रश्न

ब्राउज़र हिस्ट्री को तोड़े बिना आप एक SPA नेविगेशन लेयर को recoverable और observable बनाने के लिए इसे कैसे पुनर्गठित (redesign) करेंगे? लोडिंग रेस, एरर रिकवरी, स्क्रॉल रिस्टोरेशन और Navigation API अनुपलब्ध होने पर फ़ॉलबैक की व्याख्या करें।

प्रश्न और संदर्भ

ब्राउज़र हिस्ट्री को तोड़े बिना आप एक SPA नेविगेशन लेयर को recoverable और observable बनाने के लिए इसे कैसे पुनर्गठित (redesign) करेंगे? लोडिंग रेस, एरर रिकवरी, स्क्रॉल रिस्टोरेशन और Navigation API अनुपलब्ध होने पर फ़ॉलबैक की व्याख्या करें।

यह प्रश्न frontend, full-stack और web-platform भूमिकाओं के लिए उपयुक्त है। यह रटे-रटाए फ़्रेमवर्क कॉन्फ़िगरेशन के बजाय ब्राउज़र नेविगेशन मॉडल, एसिंक्रोनस स्टेट मशीनों और progressive enhancement का परीक्षण करता है। Navigation API समान-दस्तावेज़ (same-document) नेविगेशन का एक एकीकृत दृश्य प्रदान करता है जो navigate, navigatesuccess, और navigateerror जैसे इवेंट्स के साथ-साथ intercept() के माध्यम से काम करता है। यह सर्वर-रेंडर्ड प्रारंभिक लोड को प्रतिस्थापित नहीं करता है और न ही क्रॉस-डॉक्यूमेंट नेविगेशन की सुरक्षा सीमा को बदलता है।

इंटरव्यूअर्स क्या आंकते हैं

  • URL और हिस्ट्री एंट्री को केवल कंपोनेंट मेमोरी के बजाय नेविगेशन स्टेट के रूप में मानना।
  • Same-document रूट्स को डॉक्यूमेंट्स, डाउनलोड्स, फॉर्म्स और क्रॉस-ओरिजिन लिंक्स से अलग पहचानना।
  • बासी (stale) रिक्वेस्ट्स, कैंसलेशन, एरर्स और बैक/फ़ॉरवर्ड नेविगेशन को संभालना।
  • स्क्रॉल, फ़ोकस और पेज-स्टेट रिस्टोरेशन के नियमों को परिभाषित करना।
  • पहले लोड और असमर्थित (unsupported) ब्राउज़रों को कार्यात्मक बनाए रखना।
  • सफलता, विफलता, टाइमआउट, कैंसलेशन और रिकवरी को इंस्ट्रूमेंट करना।

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

“मैं सर्वर-रेंडर्ड एंट्री पॉइंट्स और सामान्य लिंक्स को चालू रखूँगा, जिसमें URL और हिस्ट्री सत्य का स्रोत (source of truth) होंगे। जब Navigation API उपलब्ध हो, तो मैं केवल same-origin एप्लिकेशन रूट्स को इंटरसेप्ट करूँगा, navigate इवेंट में कैंसल करने योग्य लोडिंग शुरू करूँगा, और एक नए नेविगेशन को पुराने वाले को कैंसल करने दूँगा। केवल वर्तमान टास्क ही व्यू को कमिट कर सकता है। सफलता पर मैं स्क्रॉल और फ़ोकस को रिस्टोर करता हूँ; विफलता पर मैं पुराने व्यू को बनाए रखता हूँ और पुनः प्रयास (retry) या रीलोड का विकल्प देता हूँ। असमर्थित ब्राउज़र मौजूदा History API पाथ का उपयोग करते हैं, जो समान लोडर और मेट्रिक्स साझा करते हैं।”

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

चरण 1: उन नेविगेशन्स को सीमित करें जिन्हें आप इंटरसेप्ट करते हैं

जाँचें कि क्या गंतव्य (destination) same-origin है, एक एप्लिकेशन रूट है, और वर्तमान दस्तावेज़ में रेंडर करने के लिए सुरक्षित है। बाहरी लिंक, डाउनलोड, क्रॉस-ओरिजिन गंतव्य, विशेष प्रोटोकॉल और फॉर्म सेमेंटिक्स को डिफ़ॉल्ट ब्राउज़र व्यवहार बनाए रखना चाहिए। पहला दस्तावेज़ अनुरोध अभी भी सर्वर और ब्राउज़र का हिस्सा है; एक navigate इवेंट अकेले किसी विफल स्क्रिप्ट लोड को रिकवरेबल नहीं बना सकता है।

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

चरण 2: नेविगेशन को कैंसल करने योग्य (cancellable) बनाएं

प्रत्येक नेविगेशन के लिए एक बढ़ता हुआ सीक्वेंस नंबर असाइन करें और इसका AbortSignal डेटा लोडर्स को पास करें। यदि कोई उपयोगकर्ता /search?q=a से /search?q=ab पर जाता है, तो पहले अनुरोध से आने वाला विलंबित रिस्पॉन्स दूसरे वाले को ओवरराइट नहीं करना चाहिए। कमिट करने से पहले, जाँचें कि सिग्नल अबॉर्ट न हुआ हो, सीक्वेंस वर्तमान हो, और गंतव्य अभी भी इच्छित स्थिति से मेल खाता हो।

js
let latestNavigation = 0;

navigation.addEventListener("navigate", (event) => {
  if (!event.canIntercept || !isAppRoute(event.destination.url)) return;
  const id = ++latestNavigation;
  event.intercept({
    async handler() {
      const data = await loadRoute(event.destination.url, event.signal);
      if (event.signal.aborted || id !== latestNavigation) return;
      renderRoute(data);
    }
  });
});

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

चरण 3: हिस्ट्री, स्क्रॉल और पेज स्टेट कमिट करें

सफल नेविगेशन के बाद, परिणाम के रूप में गंतव्य URL को कमिट करें। यदि कोई छोटा रिकवरेबल मान वर्तमान हिस्ट्री एंट्री से संबंधित है, तो updateCurrentEntry() इसे स्टोर कर सकता है; बड़े ऑब्जेक्ट्स और संवेदनशील डेटा वहाँ के लिए नहीं हैं। स्क्रॉल पॉलिसी को एक नए रूट, बैक/फ़ॉरवर्ड और एक एंकर के बीच अंतर करना चाहिए: नए रूट आमतौर पर शीर्ष से शुरू होते हैं, जबकि हिस्ट्री ट्रैवर्सल सहेजी गई स्थिति को रिस्टोर करता है।

लोड की शुरुआत में टाइटल, चयनित आइटम या ब्रेडक्रम्ब को बदलने से बचें, जब तक कि UI स्पष्ट रूप से एक पेंडिंग स्थिति का प्रतिनिधित्व न करता हो। सफलता के बाद मुख्य विज़ुअल स्टेट को कमिट करें, और विफलता के बाद पुनः प्रयास (retry) कार्रवाई के साथ पुरानी सामग्री को बनाए रखें। navigatesuccess और navigateerror लेटेंसी, कैंसलेशन और विफलता मेट्रिक्स के लिए उपयोगी ऑब्जर्वेशन पॉइंट्स हैं।

चरण 4: त्रुटियों (Errors) से उबरें

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

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

चरण 5: Progressive enhancement लागू करें

Navigation API समर्थन बेसलाइन History API की तुलना में नया है, इसलिए यह एकमात्र मार्ग नहीं हो सकता है। window.navigation और वास्तव में आपके द्वारा उपयोग किए जाने वाले तरीकों का पता लगाएं, फिर एन्हांस्ड पाथ का चयन करें। असमर्थित ब्राउज़रों को मौजूदा History API या फ़्रेमवर्क राउटर के माध्यम से समान रूट लोडर का पुन: उपयोग करना चाहिए; केवल अनुकूलता के लिए व्यावसायिक नियमों (business rules) को अलग न करें।

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

चरण 6: परफ़ॉर्मेंस और एक्सेसिबिलिटी सत्यापित करें

वास्तविक कार्यों का उपयोग करें: खोज, फ़िल्टरिंग, बैक, रीफ़्रेश, डीप लिंक और पुनः प्रयास। ब्राउज़र क्षमता के अनुसार समूहीकृत करते हुए टाइम टू इंटरएक्टिव, कैंसलेशन दर, विफलता दर, फ़ॉलबैक दर और डुप्लिकेट अनुरोधों को मापें। केवल कंपोनेंट रेंडर समय डेटा, अनुमति या हिस्ट्री विफलताओं की व्याख्या नहीं कर सकता है।

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

सूचना लाभ और सीमाएं

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

मॉडल उत्तर

“मैं नेविगेशन को same-origin एप्लिकेशन रूट्स, पूर्ण दस्तावेज़ों, डाउनलोड्स, फॉर्म्स और क्रॉस-ओरिजिन गंतव्यों में वर्गीकृत करूँगा, और केवल पहले वर्ग को ही इंटरसेप्ट करूँगा। सर्वर एंट्री पॉइंट्स और सामान्य लिंक वैध बने रहते हैं, जिसमें URL और हिस्ट्री सत्य का स्रोत होते हैं। Navigation API के साथ, navigate इवेंट intercept() को कॉल करता है और एक सीक्वेंस नंबर व कैंसलेशन सिग्नल बनाता है। एक नया नेविगेशन पुराने लोड को कैंसल कर देता है, और परिणाम केवल तभी कमिट किया जाता है जब वह अभी भी वर्तमान हो।

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

यदि Navigation API अनुपलब्ध है, तो वही लोडर History API या फ़्रेमवर्क राउटर के माध्यम से चलता है; बाहरी लिंक और डाउनलोड हमेशा डिफ़ॉल्ट ब्राउज़र व्यवहार का उपयोग करते हैं। मैं डीप लिंक्स, रीफ़्रेश, तेज़ क्लिक्स, धीमे नेटवर्क्स, क्रॉस-ओरिजिन लिंक्स, स्क्रिप्ट विफलता और सहायक-तकनीक (assistive-technology) कार्यों को सत्यापित करूँगा ताकि यह सुनिश्चित हो सके कि पता, सामग्री, फ़ोकस और हिस्ट्री में कभी असहमति न हो। इसका परिणाम केवल नए ब्राउज़रों में काम करने वाले क्लाइंट-ओनली प्रतिस्थापन के बजाय एक प्रोग्रेसिव नेविगेशन लेयर होता है।”

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

  • प्रत्येक लिंक को इंटरसेप्ट करना → डाउनलोड, फॉर्म और क्रॉस-ओरिजिन सेमेंटिक्स टूट जाते हैं → केवल स्वीकृत same-origin ऐप रूट्स को इंटरसेप्ट करें।
  • अंतिम रिस्पॉन्स को जीतने देना → पुराना डेटा वर्तमान इरादे को ओवरराइट कर सकता है → कैंसलेशन और सीक्वेंस चेक्स का उपयोग करें।
  • केवल रेंडरिंग का परीक्षण करना → डेटा, अनुमति और हिस्ट्री विफलताएं छिपी रहती हैं → संपूर्ण नेविगेशन टास्क और रिकवरी का परीक्षण करें।
  • Navigation API को फ़र्स्ट-लोड इन्फ्रास्ट्रक्चर के रूप में मानना → रीफ़्रेश या स्क्रिप्ट विफलता अपूरणीय (unrecoverable) हो जाती है → सर्वर रिस्पॉन्स और सामान्य लिंक्स को बनाए रखें।
  • सभी स्टेट को हिस्ट्री एंट्रीज में डालना → एंट्रीज बहुत बड़ी हो जाती हैं या संवेदनशील डेटा उजागर करती हैं → केवल छोटा पुनर्निर्माण योग्य (reconstructable) स्टेट ही स्टोर करें।
  • फ़ॉलबैक के लिए व्यावसायिक तर्क (business logic) को डुप्लिकेट करना → एन्हांस्ड और फ़ॉलबैक पाथ्स में अंतर आ जाता है → लोडर्स, स्टेट रूल्स और मेट्रिक्स साझा करें।

फॉलो-अप प्रश्न

क्या होगा यदि किसी पुराने अनुरोध ने कैश को पहले ही भर दिया हो?

कैश राइट्स की अनुमति दी जा सकती है, लेकिन UI कमिट्स के लिए अभी भी एक वर्तमान सीक्वेंस और नॉन-अबॉर्टेड सिग्नल की आवश्यकता होती है। एंट्रीज को URL, पैरामीटर्स और वर्ज़न द्वारा की (key) करें। एक विलंबित परिणाम भविष्य के अनुरोध को वॉर्म (warm) कर सकता है, लेकिन इसे वर्तमान पेज को म्यूटेट नहीं करना चाहिए।

क्या ऑथराइजेशन विफलता पर वापस जाना चाहिए या लॉगिन पर रीडायरेक्ट करना चाहिए?

अनऑथेंटिकेटेड, अनऑथराइज्ड और गायब संसाधनों में अंतर करने के लिए स्पष्ट सर्वर स्टेटस का उपयोग करें। एक अनऑथेंटिकेटेड उपयोगकर्ता रिटर्न URL के साथ लॉगिन में प्रवेश कर सकता है; एक अनऑथराइज्ड उपयोगकर्ता को एक स्पष्टीकरण और एक सुरक्षित अगली कार्रवाई की आवश्यकता होती है। ऑथराइजेशन को एक सामान्य नेटवर्क एरर के रूप में न छिपाएं।

आप Navigation API के बिना ब्राउज़रों का परीक्षण कैसे करते हैं?

क्षमता का पता लगाकर समान डीप-लिंक, रीफ़्रेश, बैक/फ़ॉरवर्ड, स्लो-नेटवर्क और विफलता कार्यों को चलाएं, जिसमें URL, सामग्री, टाइटल, फ़ोकस और स्क्रॉल की जाँच की जाए। व्यवहार की समानता मायने रखती है; आंतरिक इवेंट सीक्वेंस का समान होना आवश्यक नहीं है।

पूरी तरह से फ़्रेमवर्क राउटर पर निर्भर क्यों न रहें?

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

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

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