Random try-catch (some places have 'try-catch', others just crash)
The Art of Random Try-Catch
Some developers enjoy randomly placing try-catch blocks in their code, like playing a game of Minesweeper. Sometimes it catches errors, and other times it crashes the app outright—this unpredictability brings endless surprises to the team. Imagine debugging a complex feature only to discover that a critical path lacks error handling, while an insignificant section is wrapped tightly in try-catch. Such experiences are truly delightful.
The Philosophy of Selective Catching
True masters of defensive programming understand that not all errors are worth catching. For example:
function calculatePrice(quantity, price) {
// NaN might occur here, but we choose to ignore it
return quantity * price;
}
function fetchUserData() {
try {
// This API call might 404, but we only care about JSON parsing
const response = await fetch('/api/user');
return response.json();
} catch (e) {
console.log('JSON parsing failed');
}
}
Notice how the second function cleverly ignores the possibility of a failed network request, catching only JSON parsing errors. This selective blindness ensures the code "appears" to work most of the time.
The Russian Doll of Nested Try-Catch
When unsure where errors might occur, nest multiple layers of try-catch within a single function:
function processOrder(order) {
try {
try {
const validation = validateOrder(order);
try {
const payment = processPayment(validation);
try {
return shipProducts(payment);
} catch (e) {
console.log('Shipping failed');
}
} catch (e) {
console.log('Payment processing failed');
}
} catch (e) {
console.log('Order validation failed');
}
} catch (e) {
console.log('Unknown error');
}
}
This approach offers many benefits: the code looks "safe," error-handling logic is scattered everywhere, and when modifications are needed, you’ll need to excavate layer by layer like an archaeologist.
Silencing Errors with Grace
The most advanced defense is letting errors disappear without a trace:
function getUserPreferences(userId) {
try {
const prefs = localStorage.getItem(`prefs_${userId}`);
return JSON.parse(prefs);
} catch {
// Do nothing
}
}
When this function returns undefined
, the caller might assume the user has no preferences set, when in reality, it could be due to disabled localStorage, JSON parsing failures, or an invalid user ID. Such silent failures create the most elusive bugs.
Inconsistent Error-Handling Strategies
Mix multiple error-handling approaches within the same project:
// Method 1: Error-first callbacks
db.query('SELECT * FROM users', (err, result) => {
if (err) throw err; // Suddenly becomes synchronous
});
// Method 2: Promise catch
api.get('/data')
.then(handleData)
.catch(() => window.location.href = '/500'); // Redirect to error page
// Method 3: Unhandled async/await
async function init() {
const data = await unsafeOperation(); // No try-catch
}
This diversity ensures everyone reading the code must relearn the project's error-handling "standards"—if they exist at all.
Catch But Don’t Handle
Catch errors only to log them, then rethrow:
function saveDocument(content) {
try {
return db.save(content);
} catch (e) {
console.error('Save failed:', e);
throw e; // Log and rethrow
}
}
This burdens the logging system without actually solving the problem—a win-win.
The Pitfall of Over-Catching
Some developers love wrapping everything in try-catch:
try {
const x = 1;
const y = 2;
try {
const sum = x + y;
try {
console.log(sum);
} catch (e) {
alert('Print failed');
}
} catch (e) {
alert('Addition failed');
}
} catch (e) {
alert('Variable declaration failed');
}
This ensures your code "gracefully" handles even JavaScript engine failures—though the odds of that happening are lower than winning the lottery.
Ignoring Error Types
Treat all errors as the same type:
try {
dangerousOperation();
} catch (e) {
// Network errors, type errors, syntax errors, business logic errors...
showToast('Something went wrong');
}
Users will appreciate the vague error messages, as they add an element of mystery and guessing games.
The Blind Spot of Async Errors
Forgetting async code also needs error handling:
// Promise without catch
function uploadFile(file) {
return new Promise((resolve) => {
reader.readAsArrayBuffer(file);
reader.onload = resolve;
});
}
// Async without try-catch
async function fetchData() {
const data = await api.get('/data');
process(data); // If process throws an error...
}
These unhandled rejections become surprise gifts in the console.
The Illusion of Global Error Handling
Relying solely on global error handling as a last resort:
// Main entry
window.addEventListener('error', () => {
document.body.innerHTML = '<h1>Something went wrong</h1>';
});
// Then no business code needs try-catch
function checkout() {
// Various errors might be thrown here
}
When errors occur, users see an unhelpful blank page, while developers lose all error context.
The Mirage of Type Safety
Pretending errors don’t exist in TypeScript:
function divide(a: number, b: number): number {
return a / b; // Runtime b might be 0
}
interface User {
name: string;
address?: {
street: string;
};
}
function getStreet(user: User) {
return user.address.street; // Happy undefined access
}
The type system gives false security, while runtime errors deliver real lessons.
Defensive Comments Instead of Defensive Code
Using comments as a substitute for actual error handling:
// Note: Error handling needed here
function parseJSON(json) {
return JSON.parse(json);
}
// Might fail
function saveToDB(data) {
db.save(data);
}
These comments are like "Drive Safely" road signs—they warn of danger but don’t prevent accidents.
Performance Considerations in Error Handling
Omitting error handling for "performance":
// Hot path code—no try-catch overhead allowed
function renderList(items) {
items.forEach(item => {
renderItem(item); // If renderItem throws...
});
}
When this function crashes, you can proudly claim it was a necessary sacrifice for performance.
Pushing All Errors to the Caller
Shifting error-handling responsibility entirely to the caller:
class API {
static async get(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(response.status);
return response.json();
}
}
// Every API call must now handle its own try-catch
async function getUser() {
try {
return await API.get('/user');
} catch (e) {
// Handle error
}
}
This design ensures your codebase is filled with repetitive error-handling logic.
Using Try-Catch for Business Logic
Creatively using try-catch for flow control:
function getUserRole(user) {
try {
checkAdminPermission(user);
return 'admin';
} catch {
try {
checkEditorPermission(user);
return 'editor';
} catch {
return 'guest';
}
}
}
This pattern turns simple conditionals into baffling exception-driven flows, significantly increasing code complexity.
Catch and Continue Execution
Pretending nothing happened after an error:
function processBatch(items) {
items.forEach(item => {
try {
transform(item);
} catch (e) {
console.log('Processing failed:', item.id);
}
});
// Continue execution despite some failures
saveResults(items);
}
This "optimistic" approach ensures errors snowball until they eventually explode.
Creatively Ignoring Error Objects
Catching errors but ignoring the error object:
try {
parseConfig();
} catch {
// No idea what went wrong, but reset to defaults
resetConfig();
}
This demonstrates the developer’s profound understanding—errors aren’t worth studying.
Hiding Errors in Layers of Abstraction
Catching errors at lower layers and converting them into vague messages:
// Data access layer
function queryDatabase(sql) {
try {
return db.query(sql);
} catch (e) {
throw new Error('Database operation failed');
}
}
// Service layer
function getProducts() {
try {
return queryDatabase('SELECT * FROM products');
} catch (e) {
throw new Error('Failed to fetch products');
}
}
// Controller layer
async function listProducts(req, res) {
try {
const products = await getProducts();
res.json(products);
} catch (e) {
res.status(500).send('Server error');
}
}
After such层层包装, the original error message becomes unrecognizable, like a game of telephone.
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn