Error handling mechanism
Error Handling Mechanism
The error handling mechanism in JavaScript is a crucial part of ensuring code robustness. When exceptions occur during code execution, without proper handling mechanisms, the program may crash or produce unexpected behavior. Through reasonable error handling, these exceptions can be captured and managed, ensuring the program can continue gracefully or provide meaningful feedback.
try-catch Statement
try-catch
is the most basic error handling structure. The try
block contains code that might throw an error, while the catch
block captures and handles these errors.
try {
// Code that might throw an error
const result = someFunctionThatMightFail();
console.log(result);
} catch (error) {
// Handle the error
console.error('An error occurred:', error.message);
}
The catch
block receives an error object, typically containing a message
property describing the error details. You can also access the name
and stack
properties to get the error type and call stack information.
finally Block
The finally
block executes regardless of whether an error occurs, often used for resource cleanup.
let fileHandle;
try {
fileHandle = openFile('example.txt');
processFile(fileHandle);
} catch (error) {
console.error('File processing failed:', error);
} finally {
if (fileHandle) {
closeFile(fileHandle);
}
}
Error Types
JavaScript has several built-in error types, which can be checked using instanceof
:
try {
// Code that might throw different types of errors
} catch (error) {
if (error instanceof TypeError) {
console.error('Type error:', error.message);
} else if (error instanceof ReferenceError) {
console.error('Reference error:', error.message);
} else {
console.error('Unknown error:', error.message);
}
}
Common built-in error types include:
Error
: Generic base error classSyntaxError
: Syntax errorTypeError
: Type errorReferenceError
: Reference errorRangeError
: Numeric value out of rangeURIError
: URI handling errorEvalError
: eval function error
Custom Errors
You can create custom error types by extending the Error
class:
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
function validateUser(user) {
if (!user.name) {
throw new ValidationError('Name is required', 'name');
}
if (!user.email) {
throw new ValidationError('Email is required', 'email');
}
}
try {
validateUser({});
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation failed for ${error.field}: ${error.message}`);
} else {
console.error('Unknown error:', error);
}
}
throw Statement
Use throw
to actively throw an error. While any value can be thrown, the best practice is to throw an instance of Error
or its subclasses.
function divide(a, b) {
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
}
try {
const result = divide(10, 0);
console.log(result);
} catch (error) {
console.error('Division error:', error.message);
}
Promise Error Handling
Promises use the .catch()
method to handle errors or try-catch
with async/await
.
// Using .catch()
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Fetch failed:', error));
// Using async/await
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch failed:', error);
}
}
Global Error Handling
window.onerror
Captures unhandled runtime errors:
window.onerror = function(message, source, lineno, colno, error) {
console.error(`Uncaught error: ${message} at ${source}:${lineno}:${colno}`);
// Return true to prevent default error handling
return true;
};
unhandledrejection Event
Captures unhandled Promise rejections:
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled rejection:', event.reason);
// Prevent default handling
event.preventDefault();
});
Error Boundaries (React)
In React, error boundaries are components that catch JavaScript errors in their child component tree:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
Error Logging
In production environments, errors should be logged to a server:
function logError(error) {
const errorData = {
message: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href
};
fetch('/api/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorData)
}).catch(loggingError => {
console.error('Failed to log error:', loggingError);
});
}
window.addEventListener('error', event => {
logError(event.error);
});
window.addEventListener('unhandledrejection', event => {
logError(event.reason);
});
Defensive Programming
Defensive programming practices combined with error handling:
// 1. Parameter validation
function createUser(userData) {
if (!userData || typeof userData !== 'object') {
throw new TypeError('User data must be an object');
}
// ...
}
// 2. Default values and optional chaining
function getAddress(user) {
return user?.address?.street ?? 'Unknown';
}
// 3. Nullish coalescing
const config = userConfig ?? defaultConfig;
// 4. Type checking
function calculateTotal(items) {
if (!Array.isArray(items)) {
throw new TypeError('Items must be an array');
}
// ...
}
Error Handling in Async Iterators
Special attention is needed when handling errors in async iterators:
async function processAsyncIterable(asyncIterable) {
try {
for await (const item of asyncIterable) {
console.log(item);
}
} catch (error) {
console.error('Async iteration failed:', error);
}
}
// Example usage
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
async next() {
if (i++ < 3) {
await new Promise(resolve => setTimeout(resolve, 100));
return { value: i, done: false };
}
throw new Error('Async iteration error');
}
};
}
};
processAsyncIterable(asyncIterable);
Error Handling in Node.js
Node.js has some specific error handling patterns:
// 1. Error-first callback convention
fs.readFile('file.txt', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log(data.toString());
});
// 2. EventEmitter error handling
const eventEmitter = new EventEmitter();
eventEmitter.on('error', err => {
console.error('Emitter error:', err);
});
// 3. Using the domain module (deprecated, but important to understand the concept)
Performance Considerations
Impact of error handling on performance:
try-catch
blocks have minimal performance overhead when no errors are thrown- Frequently throwing and catching errors can impact performance
- Avoid complex error handling in hot code paths
- Minimize the data volume of error logs in production
// Bad practice: Using try-catch inside a loop
for (let i = 0; i < 1000000; i++) {
try {
riskyOperation();
} catch (e) {
// ...
}
}
// Better practice: Wrap the entire loop in try-catch
try {
for (let i = 0; i < 1000000; i++) {
riskyOperation();
}
} catch (e) {
// ...
}
Testing Error Scenarios
Write tests to verify error handling logic:
// Using Jest to test error throwing
test('divide throws error when dividing by zero', () => {
expect(() => divide(10, 0)).toThrow('Division by zero');
expect(() => divide(10, 0)).toThrow(Error);
});
// Testing async errors
test('async function rejects properly', async () => {
await expect(fetchData('invalid-url')).rejects.toThrow('Network error');
});
// Testing React error boundaries
test('ErrorBoundary catches child errors', () => {
const ErrorComponent = () => {
throw new Error('Test error');
};
const wrapper = mount(
<ErrorBoundary>
<ErrorComponent />
</ErrorBoundary>
);
expect(wrapper.text()).toContain('Something went wrong');
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn