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

कोडिंग इंटरव्यू: आप JavaScript एक्सप्लिसिट रिसोर्स मैनेजमेंट का सुरक्षित रूप से उपयोग कैसे करेंगे?

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

प्रश्न

एक रिक्वेस्ट हैंडलर एक फ़ाइल, एक टाइमर और एक एसिंक्रोनस लॉक खोलता है। दिखाएं कि आप Symbol.dispose, Symbol.asyncDispose, using, और await using का उपयोग करके सफलता, विफलता और रद्दीकरण पर प्रत्येक रिसोर्स को कैसे रिलीज़ करेंगे। स्कोप, डिस्पोज़ल क्रम, एरर हैंडलिंग, फीचर डिटेक्शन और टेस्ट्स की व्याख्या करें।

प्रॉम्प्ट और स्कोप

हैंडलर सिंक्रोनस और एसिंक्रोनस रिसोर्सेज प्राप्त करता है जिनका लाइफटाइम एक ब्लॉक सीमा पर समाप्त होना चाहिए। एक सुरक्षित रैपर डिज़ाइन करने के लिए JavaScript के एक्सप्लिसिट रिसोर्स-मैनेजमेंट प्रोटोकॉल का उपयोग करें, फिर समझाएं कि निर्माण, बॉडी निष्पादन, या क्लीनअप विफल होने पर क्या होता है। उत्तर में भाषा सिंटैक्स को रनटाइम और लाइब्रेरी समर्थन से अलग किया जाना चाहिए; TypeScript 5.2 सिंटैक्स की टाइप-चेक कर सकता है, जबकि प्रोडक्शन उपलब्धता अभी भी टारगेट इंजन और ट्रांसपाइलेशन रणनीति पर निर्भर करती है।

यह एक coding प्रश्न है क्योंकि मूल कौशल रिसोर्स-लाइफटाइम रीजनिंग और विफलता-सुरक्षित कार्यान्वयन है, न कि किसी फ्रेमवर्क का चयन।

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

पहला, क्या आप सिंक्रोनस क्लीनअप के लिए [Symbol.dispose]() और ऐसे क्लीनअप के लिए जिसे अवेट किया जाना चाहिए [Symbol.asyncDispose]() के साथ एक रिसोर्स को परिभाषित कर सकते हैं?

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

तीसरा, क्या आप डिस्पोज़ल क्रम बता सकते हैं? रिसोर्सेज को घोषणा के विपरीत क्रम में डिस्पोज़ किया जाता है, इसलिए निर्भर रिसोर्सेज को उन रिसोर्सेज के बाद घोषित किया जाना चाहिए जिन पर वे निर्भर हैं।

चौथा, क्या आप त्रुटियों के बारे में तर्क कर सकते हैं? बॉडी एरर और डिस्पोज़ल एरर दोनों को एक सप्रेस्ड एरर चेन के रूप में संरक्षित करने की आवश्यकता हो सकती है; क्लीनअप को चुपचाप प्राथमिक विफलता को प्रतिस्थापित नहीं करना चाहिए।

पांचवां, क्या आप एक अनुकूलता योजना प्रदान कर सकते हैं? जब परिनियोजन रनटाइम प्रोटोकॉल को लागू नहीं करता है, तो फीचर डिटेक्शन, एक कंपाइलर ट्रांसफ़ॉर्म, या एक स्पष्ट try/finally एडेप्टर की आवश्यकता हो सकती है।

पहले स्पष्ट करने वाले प्रश्न

  • कौन से Node.js या ब्राउज़र संस्करण कोड निष्पादित करते हैं, और क्या ट्रांसपाइलेशन की अनुमति है?
  • कौन से रिसोर्सेज सिंक्रोनस हैं, और कौन से क्लीनअप ऑपरेशंस प्रॉमिस लौटाते हैं?
  • क्या कैंसलेशन रिसोर्स को तुरंत बंद कर देता है, या इन-फ़्लाइट कार्य समाप्त हो सकता है?
  • क्या रिसोर्सेज स्वतंत्र हैं, या एक का क्लीनअप दूसरे के खुले रहने पर निर्भर करता है?
  • क्या क्लीनअप एरर्स को रिक्वेस्ट को विफल करना चाहिए, रिपोर्ट किया जाना चाहिए, या प्राथमिक एरर से जोड़ा जाना चाहिए?
  • क्या कोड DisposableStack का उपयोग कर सकता है या केवल बुनियादी सिंबल का?

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

“मैं प्रत्येक रिसोर्स को एक स्पष्ट डिस्पोज़ल प्रोटोकॉल दूंगा, इसे सबसे छोटे ब्लॉक के अंदर घोषित करूंगा जो इसके लाइफटाइम का मालिक है, और जब भी क्लीनअप एसिंक्रोनस हो तो await using का उपयोग करूंगा। मैं डिपेंडेंसीज को बाद में घोषित करूंगा ताकि रिवर्स-ऑर्डर डिस्पोज़ल सुरक्षित रहे, सफलता, बॉडी विफलता, प्राप्ति विफलता और कैंसलेशन का परीक्षण करूंगा, और बॉडी और क्लीनअप दोनों एरर्स को संरक्षित रखूंगा। शिप करने से पहले, मैं इंजन सपोर्ट को सत्यापित करूंगा या एक समकक्ष try/finally में कंपाइल करूंगा; TypeScript में सिंटैक्स सपोर्ट रनटाइम सपोर्ट की गारंटी नहीं देता है।”

चरण-दर-चरण उत्तर

चरण 1: संकीर्ण डिस्पोज़ल प्रोटोकॉल परिभाषित करें

प्राप्ति और क्लीनअप को एक साथ रखें। एक सिंक्रोनस रिसोर्स [Symbol.dispose]() को उजागर करता है और ब्लॉक से बाहर निकलने से पहले क्लीनअप समाप्त करना चाहिए। एक एसिंक्रोनस रिसोर्स [Symbol.asyncDispose]() को उजागर करता है और इसे await using के साथ प्राप्त किया जाता है ताकि जनरेट किया गया निकास पथ इसका इंतजार करे।

ts
class FileLease {
  constructor(private readonly fd: number) {}
  [Symbol.dispose]() { closeFile(this.fd) }
}

class AsyncLockLease {
  constructor(private readonly release: () => Promise<void>) {}
  async [Symbol.asyncDispose]() { await this.release() }
}

यदि कोई कॉलर स्पष्ट रूप से रद्द भी कर सकता है तो विधियों को इडेम्पोटेंट होना चाहिए। [Symbol.dispose]() से कभी भी प्रॉमिस न लौटाएं; अवेट किए जाने वाले कार्य के लिए async प्रोटोकॉल का उपयोग करें।

चरण 2: लाइफटाइम ब्लॉक को छोटा रखें

केवल उस स्कोप में प्रवेश करने के बाद ही लीज प्राप्त करें जो इसका मालिक है। एक लंबे समय तक चलने वाले ऑब्जेक्ट में using वेरिएबल को संग्रहीत करने से बचें; इसका क्लीनअप लेक्सिकल ब्लॉक से बंधा होता है, न कि गारबेज कलेक्शन से।

ts
async function handle() {
  {
    using file = openFileLease()
    await using lock = await acquireLockLease()
    await writeWithLock(file, lock)
  }
}

यहाँ लॉक को फ़ाइल के बाद घोषित किया गया है, इसलिए लॉक पहले रिलीज़ होता है और फ़ाइल दूसरे स्थान पर बंद होती है। यदि बॉडी थ्रो करती है, तब भी दोनों निकास चलते हैं।

चरण 3: प्राप्ति और कैंसलेशन को संभालें

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

चरण 4: विफलता की जानकारी सुरक्षित रखें

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

चरण 5: अनुकूलता की योजना बनाएं

केवल TypeScript कंपाइलर ही नहीं, बल्कि वास्तविक डिप्लॉयमेंट इंजन की जाँच करें। जब नेटिव सिंटैक्स या सिंबल उपलब्ध न हों, तो try/finally में कंपाइल करें, एक जाँचे-परखे पॉलीफ़िल का उपयोग करें, या रिसोर्सेज को एप्लिकेशन-स्तरीय डिस्पोज़ेबल हेल्पर में लपेटें। फ़ॉलबैक सिमेंटिक्स को समान रखें: रिवर्स ऑर्डर, केवल एक बार क्लीनअप, अवेटेड एसिंक रिलीज़ और संरक्षित एरर्स।

चरण 6: लाइफसाइकिल सीमाओं का परीक्षण करें

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

मॉडल उत्तर

“मैं प्रत्येक हैंडल को एक डिस्पोज़ेबल लीज के रूप में मॉडल करता हूँ। सिंक्रोनस हैंडल [Symbol.dispose] को लागू करते हैं; एसिंक्रोनस रिलीज़ [Symbol.asyncDispose] को लागू करते हैं। मैं उन्हें सबसे छोटे स्वामित्व वाले ब्लॉक के अंदर बनाता हूँ, लॉक के लिए await using का उपयोग करता हूँ, और फ़ाइल के बाद लॉक घोषित करता हूँ ताकि रिवर्स-ऑर्डर क्लीनअप निर्भरता का सम्मान करे। स्कोप रिटर्न, थ्रो और कैंसलेशन पर बाहर निकलता है, इसलिए भाषा प्रोटोकॉल द्वारा क्लीनअप की गारंटी दी जाती है।

मैं प्राप्ति विफलता, बॉडी विफलता, क्लीनअप विफलता और उनके संयोजन का परीक्षण करता हूँ, प्राथमिक एरर के साथ-साथ सप्रेस्ड क्लीनअप जानकारी को सुरक्षित रखता हूँ। मैं इडेम्पोटेंस और अबॉर्ट व्यवहार को भी सत्यापित करता हूँ। अंत में, मैं प्रोडक्शन इंजन की जाँच करता हूँ: TypeScript 5.2 सपोर्ट कंपाइल-टाइम मदद है, इसका प्रमाण नहीं कि रनटाइम सिंबल को लागू करता है। यदि समर्थन गायब है, तो मैं ट्रांसपाइल करता हूँ या उसी क्रम और एरर सिमेंटिक्स के साथ एक स्पष्ट try/finally एडेप्टर का उपयोग करता हूँ।”

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

  • किसी रिसोर्स को लंबे समय तक चलने वाले स्कोप में रखना → क्लीनअप में देरी होती है → इसे सबसे छोटे स्वामित्व वाले ब्लॉक से बांधें।
  • एसिंक क्लीनअप के लिए using का उपयोग करना → एक प्रॉमिस को अनदेखा किया जा सकता है → await using के साथ [Symbol.asyncDispose] को लागू करें और उपयोग करें।
  • निर्भरता को पहले घोषित करना → रिवर्स ऑर्डर इसे बहुत जल्दी बंद कर देता है → निर्भर रिसोर्सेज को बाद में घोषित करें।
  • यह मानना कि TypeScript समर्थन का अर्थ रनटाइम समर्थन है → प्रोडक्शन पार्स या सिंबल लुकअप पर विफल रहता है → इंजन की जाँच करें या फ़ॉलबैक कंपाइल करें।
  • क्लीनअप विफलता के साथ बॉडी एरर को ओवरराइट करना → मूल कारण खो जाता है → प्राथमिक एरर और सप्रेस्ड क्लीनअप विवरण को सुरक्षित रखें।
  • दोहरे रिलीज़ की अनुमति देना → क्लीनअप असुरक्षित हो जाता है → डिस्पोज़ल को इडेम्पोटेंट बनाएं या इसे सुरक्षित करें।
  • केवल सफलता का परीक्षण करना → विफलता पथ रिसोर्स लीक करते हैं → प्राप्ति, बॉडी, कैंसलेशन और डिस्पोज़ल त्रुटियों का परीक्षण करें।

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

फॉलो-अप 1: क्या using गारबेज कलेक्शन की जगह लेता है?

नहीं। यह हैंडल और लॉक जैसे रिसोर्सेज के लिए नियतात्मक स्कोप-आधारित क्लीनअप देता है; मेमोरी रीक्लेमेशन रनटाइम का काम बना रहता है।

फॉलो-अप 2: डिस्पोज़ल रिवर्स ऑर्डर में क्यों होता है?

बाद की घोषणाएं आमतौर पर पहले वाली घोषणाओं पर निर्भर करती हैं। रिवर्स ऑर्डर आश्रित को उसकी निर्भरता बंद होने से पहले रिलीज़ होने देता है।

फॉलो-अप 3: क्लीनअप कब एसिंक्रोनस होना चाहिए?

एसिंक प्रोटोकॉल का उपयोग तब करें जब रिलीज़ को स्वयं एक अवेटेड ऑपरेशन की आवश्यकता हो, जैसे कि फ्लशिंग या रिमोट कोऑर्डिनेटर को लीज वापस करना।

फॉलो-अप 4: क्या होगा यदि बॉडी एरर और क्लीनअप एरर दोनों होते हैं?

बॉडी एरर को प्राथमिक के रूप में सुरक्षित रखें और रनटाइम के सप्रेस्ड-एरर तंत्र या समकक्ष स्पष्ट एरर चेन के माध्यम से क्लीनअप विफलता को उजागर करें।

फॉलो-अप 5: क्या किसी रिसोर्स को मैन्युअल रूप से भी डिस्पोज़ किया जा सकता है?

हाँ, लेकिन ऑपरेशन को इडेम्पोटेंट बनाएं या स्वामित्व का समन्वय करें ताकि स्कोप निकास इसे दो बार रिलीज़ न करे।

फॉलो-अप 6: नेटिव सपोर्ट के बिना फ़ॉलबैक क्या है?

एक कंपाइलर ट्रांसफ़ॉर्म, एक जाँचे-परखे पॉलीफ़िल, या एक छोटे try/finally एडेप्टर का उपयोग करें जो रिवर्स ऑर्डर, अवेटिंग, केवल-एक-बार क्लीनअप और एरर चेनिंग को बनाए रखता है।

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

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

संबंधित इंटरव्यू टूल

कोडिंग प्रॉम्प्ट के लिए स्क्रीनशॉट का उपयोग करें

समस्या को कैप्चर करें, फिर क्रम से प्रतिबंधों (constraints), समाधान, कोड, एज केस और जटिलता पर काम करें।

टूल देखें