प्रॉम्प्ट और स्कोप
एक सर्च API को देखते हुए, एक पुन: प्रयोज्य (reusable) ऑटोकमप्लीट कंपोनेंट डिज़ाइन करें। जब यूज़र 300 ms के लिए टाइप करना बंद कर दे, तो इसे अधिकतम 10 सुझावों का अनुरोध करना चाहिए, और API की p95 लेटेंसी 400 ms है। डेस्कटॉप और मोबाइल पर, इसे कीबोर्ड, माउस, टच, स्क्रीन रीडर और IME इनपुट का समर्थन करना चाहिए, और तेज़ टाइपिंग के दौरान इसे कभी भी पुरानी क्वेरी के परिणाम नहीं दिखाने चाहिए। कंपोनेंट API, स्टेट मॉडल, एसिंक्रोनस अनुरोधों, एक्सेसिबिलिटी सिमेंटिक्स, कैशिंग, एरर हैंडलिंग और टेस्टिंग की व्याख्या करें।
ये संख्याएँ इंटरव्यू की धारणाएँ हैं। बेस स्कोप फ्रंटएंड कंपोनेंट है; सर्वर-साइड रैंकिंग, स्पेल करेक्शन, पर्सनलाइज़ेशन, मल्टी-सेलेक्ट और इनफिनिट स्क्रॉलिंग स्कोप से बाहर हैं। परिणाम प्लेन टेक्स्ट या कस्टम-रेंडर की गई पंक्ति हो सकता है, लेकिन प्रत्येक परिणाम में एक स्थिर (stable) ID और पढ़ने योग्य लेबल होना चाहिए। कंपोनेंट सिंगल-सेलेक्ट सुझाव सूची के साथ एक संपादन योग्य (editable) कॉम्बोबॉक्स पैटर्न का पालन करता है।
यह प्रश्न फ्रंटएंड और फुल-स्टैक भूमिकाओं के लिए उपयुक्त है। इसके मुख्य कौशल ब्राउज़र UI, एसिंक्रोनस स्टेट और एक्सेसिबल इंटरैक्शन हैं, इसलिए श्रेणी frontend है। मौजूदा Trie लेख प्रीफिक्स लुकअप को डेटा-स्ट्रक्चर समस्या मानता है और Top K का उल्लेख केवल फॉलो-अप के रूप में करता है। यहाँ सर्च API एक दी गई निर्भरता (dependency) है; स्वतंत्र समस्या क्लाइंट-साइड रेस, फोकस सिमेंटिक्स, IME व्यवहार और एक सत्यापन योग्य (verifiable) इंटरैक्शन कॉन्ट्रैक्ट है।
इंटरव्यूअर क्या मूल्यांकन करता है
पहला संकेत यह है कि क्या उम्मीदवार अनुरोधों की संख्या कम करने (request reduction) को शुद्धता (correctness) से अलग करता है। 300 ms का डिबाउंस निरंतर टाइपिंग के दौरान अनुरोधों को कम करता है, लेकिन यह एक पुराने अनुरोध को नए अनुरोध के बाद लौटने से नहीं रोकता है। एक मजबूत उत्तर रद्दीकरण (cancellation) को एक मोनोटोनिक रूप से बढ़ते अनुरोध अनुक्रम (request sequence) के साथ जोड़ता है और केवल वर्तमान क्वेरी के लिए नवीनतम अनुरोध को ही परिणाम कमिट करने देता है।
दूसरा संकेत यह है कि क्या एक्सेसिबिलिटी सिमेंटिक्स एक पूर्ण कॉन्ट्रैक्ट बनाते हैं। केवल विज़ुअल स्टाइलिंग इनपुट, पॉपअप और विकल्पों को आपस में जोड़ नहीं सकती है। DOM फोकस इनपुट पर ही रहना चाहिए, जबकि aria-activedescendant सक्रिय विकल्प की पहचान करता है। aria-expanded, aria-controls, aria-autocomplete, listbox, option और aria-selected को दृश्य स्थिति के साथ लगातार बदलना चाहिए।
तीसरा संकेत टेक्स्ट इनपुट का सटीक मॉडल है। चीनी, जापानी और अन्य IME एक कंपोज़िशन सेशन के दौरान कई अपडेट उत्पन्न करते हैं। प्रत्येक मध्यवर्ती स्ट्रिंग को खोजना अप्रासंगिक अनुरोध बनाता है और उम्मीदवार चयन में हस्तक्षेप कर सकता है। कंपोनेंट को कंपोज़िशन को ट्रैक करना चाहिए और compositionend के बाद कमिट किए गए मान के लिए सर्च शेड्यूल करना चाहिए।
चौथा संकेत यह है कि क्या स्टेट और UI को सुसंगत (consistent) साबित किया जा सकता है। एक अकेला loading बूलियन और एक ऐरे छोटी क्वेरी, लोडिंग, सफलता, खाली परिणाम, विफलता और बंद पॉपअप को स्पष्ट रूप से व्यक्त नहीं कर सकते हैं। एक मजबूत उत्तर ट्रांज़िशन, स्थिर विकल्प ID, रिकवरी व्यवहार और परिणाम बदलने के बाद सक्रिय विकल्प के नियम को परिभाषित करता है, और फिर उन इनवेरिएंट्स को आउट-ऑफ-ऑर्डर प्रतिक्रियाओं, कीबोर्ड और स्क्रीन रीडर के साथ टेस्ट करता है।
उत्तर देने से पहले स्पष्ट करने वाले प्रश्न
- सुझाव चुने जाने के बाद क्या होता है? यदि यह केवल इनपुट भरता है, तो
onSelectको कॉल करें और सूची बंद करें। यदि यह तुरंत नेविगेट करता है, तो नेविगेशन विफलता और लौटने पर इनपुट रिस्टोरेशन के लिए अपने स्वयं के कॉन्ट्रैक्ट की आवश्यकता होती है। बेस डिज़ाइन इनपुट भरता है और एक कॉलबैक उत्सर्जित करता है। - इनपुट वैल्यू को कौन नियंत्रित करता है? किसी फॉर्म को
valueऔरonValueChangeकी आवश्यकता हो सकती है; एक स्टैंडअलोन सर्च बॉक्स एक अनियंत्रित प्रारंभिक मान का समर्थन कर सकता है। कंपोनेंट को अपने जीवनकाल के दौरान मोड नहीं बदलना चाहिए। - क्या परिणाम प्लेन टेक्स्ट हैं? रिच परिणामों के लिए
renderItemकी आवश्यकता होती है, लेकिनgetKeyऔरgetLabelको अभी भी एक स्थिर ID और एक्सेसिबल नाम प्रदान करना चाहिए। मनमाना HTML स्वीकार करने से इंजेक्शन का जोखिम बढ़ जाता है। - कितने अक्षर सर्च शुरू करते हैं? बेस डिफ़ॉल्ट दो है। उस सीमा के नीचे, लंबित कार्य को रद्द करें, सूची बंद करें और सक्रिय विकल्प को साफ़ करें। खाली क्वेरी के लिए इतिहास दिखाने के लिए एक अलग
aria-autocompleteऔर कैश नीति की आवश्यकता होगी। - क्या Tab सक्रिय सुझाव का चयन करता है? बेस डिज़ाइन में, नहीं; Tab विजेट से बाहर ले जाता है। यदि उत्पाद इस बात पर जोर देता है कि Tab सुझाव स्वीकार करता है, तो उस व्यवहार को सामान्य फोकस मूवमेंट को चुपचाप ओवरराइड करने के बजाय स्पष्ट यूज़र संचार और अलग परीक्षण की आवश्यकता होती है।
- क्या किसी त्रुटि के बाद पुराने परिणाम बने रहने चाहिए? यह डिज़ाइन उन्हें साफ़ करता है और एक पुनः प्रयास करने योग्य त्रुटि दिखाता है ताकि उपयोगकर्ता पुरानी क्वेरी के सुझावों को वर्तमान क्वेरी के रूप में गलत न समझें। एक ऑफ़लाइन-फ़र्स्ट उत्पाद संभावित रूप से पुराने (stale) के रूप में चिह्नित कैश प्रविष्टि दिखा सकता है, लेकिन वह एक अलग कॉन्ट्रैक्ट है।
30-सेकंड उत्तर रूपरेखा
"मैं कस्टमाइज़ेबल रेंडरिंग को हेडलेस स्टेट कंट्रोलर से अलग करूँगा। कंट्रोलर के पास क्वेरी, रिक्वेस्ट स्टेटस, पॉपअप स्टेट, एक्टिव ऑप्शन ID, IME स्टेट और नवीनतम रिक्वेस्ट सीक्वेंस का स्वामित्व होता है। कमिट किए गए इनपुट के बाद, यह 300 मिलीसेकंड के लिए डिबाउंस करता है और पिछले अनुरोध को रद्द करता है; किसी प्रतिक्रिया को कमिट करने से पहले उसे नवीनतम सीक्वेंस और वर्तमान क्वेरी दोनों से मेल खाना चाहिए। इनपुट कॉम्बोबॉक्स सिमेंटिक्स का उपयोग करता है और DOM फोकस बनाए रखता है, जबकि एरो कीज़ aria-activedescendant को अपडेट करती हैं, Enter चयन करता है, और Escape बंद करता है। सर्चिंग कंपोज़िशन समाप्त होने की प्रतीक्षा करती है, और एक अलग स्टेटस संदेश लोडिंग, परिणाम संख्या और कोई परिणाम नहीं होने की घोषणा करता है। मैं इसे रीऑर्डर की गई नेटवर्क प्रतिक्रियाओं, एक कीबोर्ड मैट्रिक्स, IME इनपुट, स्क्रीन रीडर और कैश अमान्यता (invalidation) के साथ सत्यापित करूँगा।"
चरण-दर-चरण गहन विश्लेषण
चरण 1: सीमा और सार्वजनिक API को परिभाषित करें
सर्च एल्गोरिदम सर्वर के होते हैं। कंपोनेंट को एक क्वेरी फ़ंक्शन और रेंडरिंग नीति प्राप्त होती है। एक फ्रेमवर्क-तटस्थ इंटरफ़ेस इस तरह दिख सकता है:
Autocomplete<T>({
value,
onValueChange,
fetchSuggestions(query, signal),
getKey(item),
getLabel(item),
renderItem,
onSelect,
minChars = 2,
limit = 10,
debounceMs = 300,
})fetchSuggestions एक AbortSignal स्वीकार करता है ताकि कॉलर नेटवर्क पर एक कैंसिलेशन चेन का प्रसार कर सके। getKey एक स्थिर विकल्प DOM ID प्रदान करता है, और getLabel भरण टेक्स्ट (fill text) और एक एक्सेसिबल नाम दोनों प्रदान करता है। कस्टम रेंडरिंग को कीबोर्ड, फोकस या चयन सिमेंटिक्स को प्रतिस्थापित नहीं करना चाहिए। यदि कंपोनेंट मान-परिवर्तन कॉलबैक को उजागर करता है, तो एक संरचित कारण शामिल करें जैसे कि input, selection, या clear ताकि उपभोक्ता स्ट्रिंग परिवर्तनों से उपयोगकर्ता के इरादे का अनुमान न लगाएं।
चरण 2: स्टेट मशीन के साथ रेंडरिंग को नियंत्रित करें
कोर स्टेट है:
query status = idle | loading | success | empty | error items isOpen activeId selectedItem isComposing latestRequestSeq
query वर्तमान इनपुट टेक्स्ट है; selectedItem पुष्ट चयन है। वे अलग-अलग तथ्य हैं और उन्हें एक फ़ील्ड साझा नहीं करना चाहिए। सूची केवल तभी खुल सकती है जब क्वेरी न्यूनतम लंबाई को पूरा करती है, इनपुट अभी भी एक इंटरैक्टिव संदर्भ में है, और स्टेटस में प्रदर्शित करने के लिए परिणाम या फीडबैक है। जब कोई नई क्वेरी शुरू हो तो activeId साफ़ करें। जब नए परिणाम आते हैं, तो पुरानी सक्रिय ID को केवल तभी बनाए रखें जब वह अभी भी मौजूद हो; अन्यथा इसे साफ़ करें ताकि aria-activedescendant कभी भी किसी गायब नोड को संदर्भित न करे।
empty और error अलग-अलग स्टेट्स हैं। एक खाली प्रतिक्रिया मान्य है; त्रुटि के लिए पुनः प्रयास किया जा सकता है। पॉपअप को बंद करने से क्वेरी या कैश को नष्ट करने की आवश्यकता नहीं है, लेकिन इसे isOpen और activeId को रीसेट करना होगा।
चरण 3: डिबाउंस, कैंसिलेशन और रिज़ल्ट कमिटमेंट को अलग करें
एक इनपुट इवेंट पहले query को सिंक्रोनस रूप से अपडेट करता है। यदि कंपोज़िशन सक्रिय है, नॉर्मलाइज़्ड क्वेरी में दो से कम वर्ण हैं, या यह केवल व्हाइटस्पेस है, तो टाइमर साफ़ करें, वर्तमान अनुरोध को निरस्त (abort) करें, और सूची को रीसेट करें। अन्यथा 300 ms के बाद अनुरोध शुरू करें। अनुरोध प्रवाह को स्यूडोकोड के रूप में व्यक्त किया जा सकता है:
async function search(rawQuery) { const query = normalize(rawQuery) const seq = ++latestRequestSeq
controller?.abort() controller = new AbortController() setStatus("loading")
try { const items = await fetchSuggestions(query, controller.signal) if (seq !== latestRequestSeq || query !== normalize(currentQuery)) return commit(items.slice(0, 10)) } catch (error) { if (isAbort(error)) return if (seq === latestRequestSeq && query === normalize(currentQuery)) { commitError(error) } } }
AbortController एक अधूरे Fetch अनुरोध और रिस्पॉन्स-बॉडी उपभोग को रोक सकता है, जिससे कार्य की बचत होती है। अनुरोध अनुक्रम (request sequence) शुद्धता का द्वार (correctness gate) है। एक पुराना ऑपरेशन पहले ही पूरा हो चुका हो सकता है, या एक कॉलर ऐसे डेटा लेयर का उपयोग कर सकता है जो सिग्नल का पूरी तरह से सम्मान नहीं करता है, इसलिए अकेले abort() को कॉल करना यह साबित नहीं करता है कि पुराने परिणाम नए परिणामों को ओवरराइट नहीं कर सकते।
300 ms डिबाउंस और 400 ms API p95 के साथ, अंतिम कीप्रेस से परिणामों तक p95 पथ रेंडरिंग से पहले लगभग 700 ms है। यह निष्कर्ष ट्रेड-ऑफ को स्पष्ट करता है। यदि अनुभव को तेज़ करने की आवश्यकता है, तो एक सटीक-क्वेरी कैश का उपयोग करें या अनुरोध लागत को मापने के बाद डिबाउंस को कम करें; यह दावा न करें कि 300 ms का डिबाउंस अभी भी 150 ms की अनकैश्ड प्रतिक्रिया उत्पन्न कर सकता है।
चरण 4: IME, पॉइंटर और फोकस को सही ढंग से संभालें
compositionstart isComposing को true पर सेट करता है। कंपोज़िशन के दौरान, input दृश्य टेक्स्ट को अपडेट करता है लेकिन सर्च शेड्यूल नहीं करता है। compositionend फ्लैग को साफ़ करता है और अंतिम कमिट किए गए टेक्स्ट के लिए एक सर्च शेड्यूल करता है। कंपोज़िशन सक्रिय होने के दौरान कीबोर्ड इवेंट अभी भी हो सकते हैं और isComposing की रिपोर्ट कर सकते हैं, इसलिए उस समय Enter को किसी सुझाव का चयन नहीं करना चाहिए। डेस्कटॉप अंग्रेज़ी इनपुट को हर अनुक्रम का प्रतिनिधित्व करने वाला मानने के बजाय लक्षित ब्राउज़रों में फ्रेमवर्क के इवेंट रैपर का परीक्षण करें।
माउस और टच चयन के लिए यह ध्यान रखना आवश्यक है कि क्लिक चलने से पहले इनपुट ब्लर (blur) हो सकता है, जो क्लिक किए गए विकल्प को हटा सकता है। प्राथमिक pointerdown इनपुट फोकस बनाए रख सकता है, जबकि एक click या pointerup जो मूवमेंट थ्रेशोल्ड के भीतर रहा, एक साझा पथ के माध्यम से चयन पूरा करता है। सूची को स्क्रॉल करने से सामान्य पॉइंटर मूवमेंट को चयन में नहीं बदलना चाहिए। एक बाहरी क्लिक पॉपअप को बंद कर देता है, जबकि चयन कॉलबैक अभी भी ठीक एक बार चलता है।
DOM फोकस इनपुट पर बना रहता है। पॉपअप विकल्पों को Tab अनुक्रम से बाहर रखा गया है, और Tab विजेट छोड़ने के लिए ब्राउज़र डिफ़ॉल्ट का पालन करता है। यह नेटिव टेक्स्ट-संपादन व्यवहार और सहायक-तकनीक (assistive-technology) इनपुट मोड को स्थिर रखता है।
चरण 5: कॉम्बोबॉक्स और कीबोर्ड कॉन्ट्रैक्ट लागू करें
इनपुट में एक दृश्यमान label होता है, या aria-labelledby या aria-label के माध्यम से इसका नाम प्राप्त होता है। यह role="combobox", aria-autocomplete="list", पॉपअप के साथ सिंक्रनाइज़ किए गए aria-expanded, सूची की ओर इशारा करते हुए aria-controls, और केवल तभी aria-activedescendant का उपयोग करता है जब कोई सक्रिय विकल्प मौजूद हो।
सुझाव कंटेनर role="listbox" का उपयोग करता है। प्रत्येक आइटम में role="option" और एक स्थिर DOM ID होती है, और विज़ुअल रूप से सक्रिय आइटम में aria-selected="true" भी होता है। डाउन एरो पहले विकल्प को सक्रिय बनाता है और फिर नीचे की ओर बढ़ता है; अप एरो उल्टी दिशा में चलता है जबकि DOM फोकस इनपुट पर रहता है। बेस डिज़ाइन लूप करने (wrapping) के बजाय सीमाओं पर रुक जाता है। Enter सक्रिय विकल्प को स्वीकार करता है। Escape पॉपअप को बंद करता है लेकिन इनपुट टेक्स्ट को सुरक्षित रखता है।
Left, Right, Home, End, Backspace या प्रिंट करने योग्य वर्णों को बिना शर्त इंटरसेप्ट न करें। एक संपादन योग्य कॉम्बोबॉक्स को ब्राउज़र के नेटिव सिंगल-लाइन संपादन व्यवहार को बनाए रखना चाहिए। preventDefault() को केवल तभी कॉल करें जब कंपोनेंट वास्तव में सूची मूवमेंट, चयन या बर्खास्तगी (dismissal) को संभालता है।
परिणाम सूची को हर अपडेट पर उच्च-प्राथमिकता वाला लाइव क्षेत्र बनने की आवश्यकता नहीं है। फोकस को स्थानांतरित किए बिना "सर्चिंग," "10 परिणाम," या "कोई परिणाम नहीं" की घोषणा करने के लिए एक अलग role="status" तत्व का उपयोग करें। प्रत्येक कीप्रेस पर घोषणा करने से विजेट अत्यधिक बातूनी (chatty) हो सकता है।
चरण 6: कैशिंग और विफलता पुनर्प्राप्ति (failure recovery) को सीमित करें
एक कैश कुंजी (cache key) में कम से कम नॉर्मलाइज़्ड क्वेरी, लोकेल, फ़िल्टर और डेटा संस्करण शामिल होते हैं। केवल क्वेरी द्वारा कैशिंग करने से लोकेल या फ़िल्टर परिवर्तन के बाद गलत डेटा मिलता है। TTL और क्षमता सीमा (capacity bound) दोनों के साथ एक सटीक-क्वेरी कैश का उपयोग करें। एक हिट तुरंत रेंडर हो सकता है, जिसके बाद बैकग्राउंड रीफ्रेश केवल तभी होता है जब उत्पाद की फ्रेशनेस नीति इसकी मांग करती है।
कैश की गई प्रतिक्रियाएँ अभी भी वर्तमान-क्वेरी और अनुरोध-अनुक्रम जाँचों को पास करती हैं। इनपुट साफ़ करना, परिणाम चुनना, कंपोनेंट को अनमाउंट करना, या किसी निर्भरता को बदलना टाइमर और अनुरोधों को रद्द कर देता है। सर्वर त्रुटि एक छोटी पुनः प्रयास कार्रवाई (retry action) को उजागर करती है; यह सुझाव सूची में चयन योग्य पंक्ति नहीं बनती है। पुनः प्रयास एक नया अनुरोध अनुक्रम बनाता है, इसलिए पुरानी त्रुटि बाद की सफलता को ओवरराइट नहीं कर सकती है।
असुरक्षित सर्वर मार्कअप के बजाय टेक्स्ट नोड्स या विश्वसनीय संरचित टुकड़ों के साथ मैचों को हाइलाइट करें। क्वेरी पैरामीटर को सही ढंग से एन्कोड करें, और जब तक वे वास्तव में आवश्यक न हों, पूर्ण संवेदनशील क्वेरी लॉग न करें।
चरण 7: प्रतिकूल परिदृश्यों (adversarial scenarios) के साथ इनवेरिएंट्स को सत्यापित करें
एक नियंत्रित घड़ी के साथ यूनिट परीक्षण साबित करते हैं कि 299 ms कोई अनुरोध नहीं करता है, 300 ms एक अनुरोध करता है, निरंतर टाइपिंग पिछले टाइमर को रद्द कर देती है, और दो वर्णों से छोटी क्वेरी स्थिति को रीसेट करती है। स्टेट परीक्षण सफलता, खाली परिणाम, त्रुटि, पुनः प्रयास, बंद करने और चयन को कवर करते हैं।
एक रेस टेस्ट a के लिए धीमी प्रतिक्रिया को ab के लिए तेज़ प्रतिक्रिया के बाद लाता है; अंतिम सूची में केवल ab परिणाम होने चाहिए। तीन रास्तों का अलग-अलग परीक्षण करें: एक निरस्त करने योग्य अनुरोध, एक पहले से पूरा हो चुका अनुरोध, और एक डेटा परत जो रद्दीकरण सिग्नल की उपेक्षा करती है।
इंटरैक्शन परीक्षण एरो, Enter, Escape, Tab, क्लिक, टच, बाहरी क्लिक, कंपोज़िशन और परिणाम बदलने के बाद सक्रिय विकल्प के गायब होने को कवर करते हैं। प्रत्येक चरण एक साथ दृश्य स्थिति, इनपुट मान, कॉलबैक गणना, DOM फोकस और ARIA विशेषताओं का दावा करता है।
स्वचालित एक्सेसिबिलिटी स्कैन कॉन्ट्रैक्ट के केवल एक हिस्से को पकड़ते हैं। इनपुट, लोडिंग, परिणाम घोषणा, चयन, खाली परिणाम और त्रुटि रिकवरी को पूरा करने के लिए एक कीबोर्ड और एक लक्षित स्क्रीन रीडर का उपयोग करें। समर्थित मोबाइल ब्राउज़रों में टच और सॉफ़्टवेयर कीबोर्ड का परीक्षण करें। प्रदर्शन परीक्षण अंतिम कीप्रेस से पहले इंटरैक्टिव परिणाम तक वितरण, अनुरोध रद्दीकरण दर, कैश हिट दर और निरस्त की गई पुरानी प्रतिक्रिया गणना को रिकॉर्ड करते हैं।
उच्च-गुणवत्ता वाला नमूना उत्तर
"मैं इसे एक फ्रंटएंड, सिंगल-सेलेक्ट सुझाव कंपोनेंट तक सीमित रखूँगा; एक मौजूदा API सर्च और रैंकिंग का प्रबंधन करता है। कंपोनेंट एक नियंत्रित मान, क्वेरी फ़ंक्शन, स्थिर कुंजी, पढ़ने योग्य लेबल, कस्टम पंक्ति रेंडरर और चयन कॉलबैक स्वीकार करता है। आंतरिक रूप से, क्वेरी टेक्स्ट, चुनी गई वस्तु, अनुरोध स्थिति, पॉपअप स्थिति, सक्रिय विकल्प, IME स्थिति और अनुरोध अनुक्रम अलग रहते हैं, इसलिए खाली परिणाम, त्रुटियां और बंद पॉपअप एक बूलियन में नहीं सिमटते हैं।
इनपुट तुरंत अपडेट होता है। एक बार जब इसमें दो अक्षर होते हैं और कंपोज़िशन समाप्त हो जाता है, तो मैं 300 मिलीसेकंड के लिए डिबाउंस करता हूँ, पिछले अनुरोध को रद्द करता हूँ, और एक अनुक्रमित (sequenced) अनुरोध शुरू करता हूँ। एक प्रतिक्रिया केवल तभी कमिट हो सकती है जब उसका अनुक्रम अभी भी नवीनतम हो और उसकी क्वेरी अभी भी इनपुट से मेल खाती हो। कैंसिलेशन काम बचाता है; सीक्वेंसिंग शुद्धता की गारंटी देती है। 300 प्लस 400 मिलीसेकंड की धारणाएं अनकैश्ड p95 पथ को लगभग 700 मिलीसेकंड पर रखती हैं, इसलिए वास्तविक लेटेंसी और अनुरोध लागत को डिबाउंस निर्धारित करना चाहिए।
सिमेंटिक रूप से, नामित इनपुट एक लिस्टबॉक्स को नियंत्रित करने वाला कॉम्बोबॉक्स है। DOM फोकस इनपुट पर रहता है; एरो कीज़ एक स्थिर aria-activedescendant को बदलती हैं, Enter चयन करता है, Escape बंद करता है, और Tab सामान्य रूप से बाहर निकलता है। विकल्प option और aria-selected का उपयोग करते हैं, जबकि एक अलग स्टेटस क्षेत्र लोडिंग, परिणाम संख्या और कोई परिणाम नहीं होने की घोषणा करता है। कंपोज़िशन के दौरान सर्चिंग और Enter चयन दोनों निलंबित रहते हैं।
कैश TTL और क्षमता द्वारा सीमित है और नॉर्मलाइज़्ड क्वेरी, लोकेल और फ़िल्टर द्वारा कुंजीबद्ध (keyed) है। मैं धीमी-पुरानी बनाम तेज़-नई प्रतिक्रियाओं, IME, कीबोर्ड और स्क्रीन-रीडर व्यवहार, पॉइंटर ब्लर, खाली परिणामों, पुनः प्रयास और कैश अमान्यता को सत्यापित करूँगा। सफलता का अर्थ है कि प्रत्येक दृश्य परिणाम वर्तमान क्वेरी से संबंधित है और फोकस और एक्सेसिबिलिटी स्थिति प्रत्येक ट्रांज़िशन पर दृश्य स्थिति से मेल खाती है।"
सामान्य गलतियाँ
- केवल डिबाउंस करना → डिबाउंस अनुरोधों को कम करता है लेकिन प्रतिक्रियाओं को क्रमबद्ध नहीं करता है → रद्दीकरण जोड़ें और नवीनतम अनुक्रम और वर्तमान क्वेरी दोनों पर प्रतिबद्धता (commitment) को सीमित करें।
- केवल
abort()को कॉल करना → पुराना काम पहले ही पूरा हो चुका हो सकता है या डेटा परत सिग्नल की उपेक्षा कर सकती है → रद्दीकरण को एक अनुकूलन के रूप में और अनुक्रम जांच को शुद्धता की शर्त के रूप में समझें। - एक ऐरे इंडेक्स को सक्रिय आइटम के रूप में उपयोग करना → पुन: क्रमबद्ध करने के बाद समान इंडेक्स एक अलग परिणाम की पहचान कर सकता है → एक स्थिर परिणाम ID का उपयोग करें और पुष्टि करें कि सूची को बदलने के बाद भी यह मौजूद है।
- DOM फोकस को हर विकल्प में स्थानांतरित करना → इनपुट, टेक्स्ट संपादन और सहायक-तकनीक फोकस अलग हो सकते हैं → फोकस को इनपुट पर रखें और
aria-activedescendantके माध्यम से सक्रिय आइटम को प्रदर्शित करें। - हर कीबोर्ड इवेंट को इंटरसेप्ट करना → नेटिव Home, End, एरो और IME संपादन व्यवहार टूट जाता है → केवल उन कुंजियों को इंटरसेप्ट करें जिनका कंपोनेंट वास्तव में सूची नेविगेशन, चयन या बर्खास्तगी के लिए उपयोग करता है।
- प्रत्येक IME अपडेट को खोजना → गैर-प्रतिबद्ध (uncommitted) ध्वन्यात्मक टेक्स्ट खराब अनुरोध उत्पन्न करता है, और Enter गलती से चयन कर सकता है → कंपोज़िशन सेशन को ट्रैक करें और इसके समाप्त होने के बाद ही सर्च करें।
- पूरी परिणाम सूची को एक तत्काल घोषणा बनाना → प्रत्येक इनपुट अपडेट वर्बोज़ स्पीच को ट्रिगर करता है → लोडिंग, संख्या और खाली परिणामों के लिए एक नियंत्रित
role="status"संदेश का उपयोग करें। - केवल क्वेरी द्वारा कैशिंग करना → लोकेल या फ़िल्टर परिवर्तन गलत डेटा दिखा सकते हैं → TTL और क्षमता सीमाओं के साथ कुंजी में परिणाम को प्रभावित करने वाली हर स्थिति और संस्करण डालें।
फॉलो-अप्स और उन्हें कैसे संभालें
फॉलो-अप 1: यदि सूची में 1,000 परिणाम दिखाने हों तो क्या बदलता है?
पहले आवश्यकता को चुनौती दें: ऑटोकमप्लीट को आमतौर पर प्रासंगिक सुझावों के एक छोटे सेट को रैंक और सीमित करना चाहिए। यदि किसी बड़े सेट को ब्राउज़ करना आवश्यक है, तो विंडोइंग (windowing) जोड़ें। सक्रिय विकल्प को माउंटेड रहना चाहिए, या aria-activedescendant को अपडेट करने से पहले माउंटेड विंडो में स्क्रॉल किया जाना चाहिए; विशेषता किसी वर्चुअलाइज़्ड-अवे नोड को संदर्भित नहीं कर सकती है। सार्थक स्थिति और कुल-आकार सिमेंटिक्स को उजागर करें और केवल फ्रेम-दर माप ही नहीं, बल्कि स्क्रीन रीडर के साथ उन्हें सत्यापित करें।
फॉलो-अप 2: एकाधिक पृष्ठ अनुरोधों और कैश प्रविष्टियों को कैसे साझा कर सकते हैं?
कैश स्टोरेज और अनुरोध डिडुप्लीकेशन को एक पेज-स्तरीय डेटा लेयर में स्थानांतरित करें, जबकि कंपोनेंट अभी भी केवल fetchSuggestions का उपभोग करता है। साझा कुंजियों में लोकेल, फ़िल्टर, प्राधिकरण स्कोप और डेटा संस्करण शामिल हैं। एक ही कुंजी के लिए कॉल एक Promise साझा कर सकते हैं, लेकिन प्रत्येक कंपोनेंट अपना स्वयं का अनुरोध अनुक्रम रखता है क्योंकि दो इनपुट में अलग-अलग वर्तमान क्वेरी और अनमाउंट समय हो सकते हैं।
फॉलो-अप 3: आप स्थानीय इतिहास (local history) और खाली-क्वेरी सुझाव कैसे जोड़ेंगे?
प्रत्येक स्रोत को history या remote के रूप में चिह्नित करें, फिर विलोपन, गोपनीयता और क्रॉस-डिवाइस सिंक्रनाइज़ेशन को परिभाषित करें। एक खाली क्वेरी पर इतिहास टाइप किए गए इनपुट को पूरा करने से एक अलग स्थिति है, इसलिए इसे एक स्पष्ट aria-autocomplete, शीर्षक और घोषणा नीति की आवश्यकता होती है। इतिहास चयन अभी भी स्थिर-ID कॉन्ट्रैक्ट का पालन करता है, और संवेदनशील खोजों को डिफ़ॉल्ट रूप से सहेजा नहीं जाना चाहिए।
फॉलो-अप 4: यह सर्वर रेंडरिंग और हाइड्रेशन के साथ कैसे काम करेगा?
सर्वर लेबल और खाली इनपुट को रेंडर कर सकता है, जबकि क्लाइंट इंटरैक्टिव पॉपअप का स्वामित्व रखता है। इनपुट, सूची और विकल्प ID सर्वर और क्लाइंट पर स्थिर होनी चाहिए; यादृच्छिक फ़र्स्ट-रेंडर ID हाइड्रेशन के बाद aria-controls को तोड़ सकती हैं। यदि सर्वर सुझावों को प्रीलोड करता है, तो कैश कुंजी, क्वेरी और डेटा संस्करण को एक साथ सीरियलाइज़ करें और पेलोड का पुन: उपयोग केवल तभी करें जब तीनों अभी भी मेल खाते हों।
फॉलो-अप 5: आप मल्टी-सेलेक्ट चिप्स का समर्थन करने के लिए कंपोनेंट को कैसे बदलेंगे?
यह फोकस, विलोपन और चयनित-आइटम सिमेंटिक्स को बदलता है; selectedItem को एक ऐरे से बदलना अपर्याप्त है। इनपुट और चिप्स के बीच बाएं और दाएं मूवमेंट, बैकस्पेस पुष्टिकरण, डुप्लिकेट्स, अधिकतम संख्या और स्क्रीन-रीडर घोषणाओं को परिभाषित करें। सुझाव सूची एक कॉम्बोबॉक्स बनी रह सकती है, लेकिन चयनित चिप्स को अपने स्वयं के नेविगेबल क्षेत्र और एक नए कीबोर्ड और सहायक-तकनीक परीक्षण पास की आवश्यकता होती है।