DanLevy.net

प्रश्नोत्तरी: उन्नत JS त्रुटि महारत

क्या आपके अपवाद वास्तव में विशिष्ट हैं?

क्या आप जावास्क्रिप्ट एरर्स को पूरी तरह समझते हैं?

JSON.stringify(error) क्या लौटाता है?

const error = new Error('Oops');
console.log(JSON.stringify(error));

Error ऑब्जेक्ट में गैर‑enumerable प्रॉपर्टी (message, name, stack) होती हैं, इसलिए JSON.stringify() {} लौटाता है। यह API प्रतिक्रियाओं में एरर भेजते समय अक्सर होने वाला गड़बड़ है। JSON.stringify(error, Object.getOwnPropertyNames(error)) का उपयोग करें या सीधे एक साधारण ऑब्जेक्ट बनाएं।

Error ऑब्जेक्ट की enumerable प्रॉपर्टियों पर विचार करें।

इन दोनों में क्या अंतर है?

const err = new Error('Test');
console.log(err);
console.log(JSON.stringify(err));

console.log(err) त्रुटि को उसके संदेश और स्टैक ट्रेस के साथ दिखाता है क्योंकि कंसोल में Error ऑब्जेक्ट्स के लिए विशेष हैंडलिंग होती है। JSON.stringify(err) '{}' लौटाता है क्योंकि Error की प्रॉपर्टीज़ enumerable नहीं होतीं। यह अंतर कई डेवलपर्स को API डिबग करते समय फँसाता है।

सोचें कि console.log और JSON सीरियलाइज़ेशन ऑब्जेक्ट को कैसे संभालते हैं।

इन जाँचों के परिणाम क्या हैं?

class CustomError extends Error {}
const err = new CustomError('test');
console.log(err instanceof CustomError);
console.log(err instanceof Error);
console.log(err instanceof Object);

तीनों true लौटाते हैं। CustomError Error को विस्तारित करता है, जो Object को विस्तारित करता है। instanceof ऑपरेटर पूरी प्रोटोटाइप चेन को जांचता है, इसलिए CustomError का एक इंस्टेंस भी Error और Object का इंस्टेंस होता है।

JavaScript इनहेरिटेंस की प्रोटोटाइप चेन याद करें।

मान लें कि iframeError उसी origin के iframe में बनाया गया और उसकी पैरेंट विंडो को दिया गया है।

console.log(iframeError instanceof Error);

अलग realms के Error कंस्ट्रक्टर अलग होते हैं, इसलिए यह जाँच false लौटा सकती है। Object.prototype.toString.call(obj) सामान्य cross-realm त्रुटियों को पहचान सकता है, लेकिन Symbol.toStringTag से उसका परिणाम नकली बनाया जा सकता है; यह प्रामाणिकता की जाँच नहीं है।

अलग संदर्भों में Error कंस्ट्रक्टर अलग होते हैं।

जब आप स्ट्रिंग थ्रो करते हैं तो क्या होता है?

try {
throw "Oops!";
} catch (e) {
console.log(e instanceof Error);
console.log(typeof e);
}

JavaScript किसी भी मान को थ्रो करने की अनुमति देता है। यहाँ, e instanceof Error false है और typeof e "string" है। यह उन त्रुटि‑हैंडलिंग कोड को तोड़ सकता है जो मानते हैं कि सभी पकड़ी गई अपवाद Error ऑब्जेक्ट हैं। बेहतर डिबगिंग के लिए हमेशा Error इंस्टेंस थ्रो करें।

JavaScript में केवल Error ऑब्जेक्ट ही नहीं, कोई भी मान throw किया जा सकता है।

err.name का मान क्या है?

class CustomError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
}
const err = new CustomError('test');
console.log(err.name);

err.name "CustomError" है क्योंकि this.constructor.name क्लास का नाम लौटाता है। this.name = this.constructor.name सेट करना एक सामान्य पैटर्न है जिससे कस्टम एरर क्लासेस स्टैक ट्रेस और एरर मैसेज में सही नाम दिखाते हैं।

देखें कि this.constructor.name का मान क्या है।

बिना name सेट किए आउटपुट क्या होगा?

class MyError extends Error {
// No constructor or name setting
}
const err = new MyError('test');
console.log(err.name);

यदि आप स्पष्ट रूप से this.name सेट नहीं करते हैं, तो त्रुटि Error क्लास की डिफ़ॉल्ट name प्रॉपर्टी को विरासत में ले लेती है, जो "Error" है। इसलिए कस्टम एरर क्लासों को हमेशा अपने कंस्ट्रक्टर में this.name = this.constructor.name सेट करना चाहिए।

Error की डिफ़ॉल्ट name प्रॉपर्टी में क्या होता है?

wrapper.cause.message क्या लौटाता है?

const original = new Error('Original error');
const wrapper = new Error('Wrapper',
{ cause: original }
);
console.log(wrapper.cause.message);

Error.cause (ES2022) त्रुटियों को चेन करने की अनुमति देता है ताकि मूल त्रुटि संदर्भ संरक्षित रहे। wrapper.cause मूल त्रुटि को संदर्भित करता है, इसलिए wrapper.cause.message "Original error" लौटाता है। यह निचले‑स्तर की त्रुटियों को उच्च‑स्तर के संदर्भ में रैप करने में उपयोगी है।

Error.cause त्रुटियों को जोड़ने की आधुनिक JavaScript सुविधा है।

मान लें कि यह V8/Node.js है, जहाँ Error.captureStackTrace उपलब्ध है। Error.captureStackTrace क्या करता है?

function createError(msg) {
const err = new Error(msg);
Error.captureStackTrace(err, createError);
return err;
}
const error = createError('test');

Error.captureStackTrace (V8/Node.js) स्टैक ट्रेस से निर्दिष्ट फ़ंक्शन (createError) को हटा देता है, जिससे एरर फ़ैक्टरी फ़ंक्शन उपयोगकर्ताओं को दिखाई नहीं देते। इससे साफ़ स्टैक ट्रेस मिलते हैं जो फ़ैक्टरी को कॉल किए गए स्थान को दिखाते हैं, फ़ैक्टरी खुद को नहीं।

स्टैक ट्रेस साफ़ करने की यह सुविधा V8 से संबंधित है।

त्रुटि संदेश क्या है?

function validate(value) {
if (!value) {
throw new Error(
`Value ${value} is invalid`
);
}
}
try {
validate(undefined);
} catch (e) {
console.log(e.message);
}

टेम्प्लेट लिटेरल्स इंटरपोलेशन के दौरान undefined को स्ट्रिंग "undefined" में बदल देते हैं। त्रुटि संदेश बन जाता है "Value undefined is invalid"। साफ़ संदेशों के लिए, इंटरपोलेशन से पहले value ?? 'null' या इसी तरह की जाँचों का उपयोग करने पर विचार करें।

टेम्प्लेट लिटरल इंटरपोलेशन undefined को कैसे संभालता है?

क्लाइंट को क्या भेजा जाता है?

// Express.js route
app.get('/api/data', (req, res) => {
const error = new Error('Database failed');
res.json({ error });
});

res.json() अंदर JSON.stringify() का उपयोग करता है, इसलिए Error ऑब्जेक्ट {} बन जाता है। क्लाइंट को {"error":{}} मिलता है। इसे ठीक करने के लिए, res.json({ error: error.message }) या res.json({ error: { message: error.message, name: error.name } }) का उपयोग करें।

याद करें कि JSON.stringify Error ऑब्जेक्ट का सीरियलाइज़ेशन कैसे करता है।

Promise.reject() क्या स्वीकार कर सकता है?

Promise.reject('string').catch(e =>
console.log(typeof e)
);
Promise.reject({code: 404}).catch(e =>
console.log(e.code)
);
Promise.reject(42).catch(e =>
console.log(e)
);

throw की तरह, Promise.reject() कोई भी मान स्वीकार करता है – स्ट्रिंग्स, ऑब्जेक्ट्स, नंबर आदि। यह "string", 404, और 42 प्रिंट करता है। प्रॉमिस चेन में पकड़े गए मानों के प्रकार की हमेशा जाँच करें, खासकर जब थर्ड‑पार्टी कोड गैर‑Error मानों से रिजेक्ट कर सकता है।

प्रॉमिस रिजेक्शन throw कथनों जैसे काम करते हैं।

error.code और error.errno कितने भरोसेमंद हैं?

const fs = require('fs');
fs.readFile('missing.txt', (err, data) => {
if (err) {
console.log(err.code); // 'ENOENT'
console.log(err.errno); // -2
}
});

code और errno जैसे गुण पर्यावरण‑विशिष्ट हैं (इस मामले में Node.js) और मानक Error ऑब्जेक्ट का हिस्सा नहीं हैं। ब्राउज़र त्रुटियों में ये गुण नहीं होते। हमेशा इनके अस्तित्व की जाँच करें: if (err.code === 'ENOENT') बजाय यह मानने के कि वे मौजूद हैं।

अलग JavaScript वातावरण और त्रुटि प्रकारों पर विचार करें।

इन जाँचों का परिणाम क्या है?

const fakeError = {
name: 'Error',
message: 'Fake error',
stack: 'fake stack'
};
console.log(fakeError instanceof Error);
console.log(Object.prototype.toString.call(
fakeError
) === '[object Error]');

इस विशेष ऑब्जेक्ट के लिए दोनों तुलनाएँ false हैं। इसका प्रोटोटाइप Error.prototype नहीं है और डिफ़ॉल्ट टैग [object Object] है। लेकिन [Symbol.toStringTag]: "Error" जोड़ने पर दूसरी तुलना true हो जाएगी। टैग का मिलना या ये फ़ील्ड मौजूद होना साबित नहीं करता कि ऑब्जेक्ट वास्तविक Error है।

एक जाँच प्रोटोटाइप चेन देखती है, दूसरी ऑब्जेक्ट का टैग।

त्रुटि‑हैंडलिंग की कला में निपुण बनें

सीरियलाइज़ेशन के फंदों से लेकर क्रॉस‑कॉन्टेक्स्ट instanceof विफलताओं तक, ये उन्नत अवधारणाएँ जूनियर डेवलपर्स को सीज़नड क्षतिग्रस्त पेशेवरों से अलग करती हैं।

और अधिक चुनौतियों के लिए तैयार हैं? हमारे पूरा क्विज़ संग्रह में जाएँ और जावास्क्रिप्ट, एल्गोरिदम और अन्य विषयों पर अतिरिक्त दिमागी पहेलियों को देखें!