第 35 章 错误处理
第 35 章 错误处理
程序不可能永远正确运行。错误处理就是让程序在出问题时能够优雅地"认错",而不是直接崩溃。
35.1 错误处理基础
try…catch / try…catch…finally
1
2
3
4
5
6
7
8
9
10
11
| try {
// 尝试执行这段代码
const result = riskyOperation();
console.log('操作成功:', result);
} catch (error) {
// 如果出错,执行这里
console.error('出错了:', error.message);
} finally {
// 不管成功还是失败,都会执行
console.log('无论成功失败,我都会执行');
}
|
Error 对象:message / name / stack
1
2
3
4
5
6
7
| try {
throw new Error('出错了!');
} catch (error) {
console.log('错误信息:', error.message); // 错误信息
console.log('错误名称:', error.name); // Error
console.log('错误堆栈:', error.stack); // 详细错误位置
}
|
内置错误类型:ReferenceError / TypeError / SyntaxError / RangeError / URIError
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| // ReferenceError:引用错误
try {
console.log(undefinedVariable); // 未定义的变量
} catch (e) {
console.log(e.name); // 打印结果: ReferenceError
}
// TypeError:类型错误
try {
null.method(); // null 没有方法
} catch (e) {
console.log(e.name); // 打印结果: TypeError
}
// SyntaxError:语法错误(只能在解析阶段捕获,不能在 try...catch 中捕获)
// try {
// eval('const = 1'); // 语法错误无法捕获
// } catch (e) {
// console.log(e.name);
// }
// RangeError:范围错误
try {
const arr = new Array(-1); // 数组长度不能为负数
} catch (e) {
console.log(e.name); // 打印结果: RangeError
}
// URIError:URI 错误
try {
decodeURIComponent('%'); // 无效的 URI 编码
} catch (e) {
console.log(e.name); // 打印结果: URIError
}
|
throw:手动抛出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 抛出字符串
throw '出错了!';
// 抛出数字
throw 404;
// 抛出对象
throw {
code: 'NOT_FOUND',
message: '资源未找到'
};
// 抛出 Error 对象
throw new Error('出错了!');
|
Error.cause(ES2022+)
1
2
3
4
5
6
7
8
9
10
11
| try {
try {
JSON.parse('invalid json');
} catch (e) {
// 在捕获错误时,附加 cause 信息
throw new Error('解析失败', { cause: e });
}
} catch (e) {
console.log(e.message); // 打印结果: 解析失败
console.log(e.cause); // 打印结果: SyntaxError: Unexpected token 'i'
}
|
自定义错误类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
function validateAge(age) {
if (typeof age !== 'number') {
throw new ValidationError('年龄必须是数字', 'age');
}
if (age < 0 || age > 150) {
throw new ValidationError('年龄必须在 0-150 之间', 'age');
}
}
try {
validateAge('abc');
} catch (e) {
if (e instanceof ValidationError) {
console.log('验证错误:', e.message, '字段:', e.field);
} else {
console.log('其他错误:', e.message);
}
}
|
下一节,我们来学习异步错误处理!
35.2 异步错误处理
try…catch 对 Promise 无效(同步代码中捕获)
1
2
3
4
5
6
7
8
9
| // ❌ try...catch 不能捕获异步代码中的错误
try {
setTimeout(function() {
throw new Error('异步错误!');
}, 1000);
} catch (e) {
console.log('捕获到了?'); // 不会执行!
}
console.log('try...catch 之外的代码'); // 立即执行
|
async/await 的错误处理:try…catch
1
2
3
4
5
6
7
8
9
10
11
12
| async function fetchData() {
try {
const response = await fetch('https://invalid-url');
const data = await response.json();
return data;
} catch (error) {
console.log('请求失败:', error.message);
return null;
}
}
fetchData();
|
Promise 的 .catch()
1
2
3
4
5
6
7
| fetch('https://invalid-url')
.then(function(response) {
return response.json();
})
.catch(function(error) {
console.log('请求失败:', error.message);
});
|
下一节,我们来学习全局错误处理!
35.3 全局错误处理
window.onerror
1
2
3
4
5
6
7
8
9
10
11
12
13
| window.onerror = function(message, source, lineno, colno, error) {
console.log('错误信息:', message);
console.log('错误来源:', source);
console.log('行号:', lineno);
console.log('列号:', colno);
console.log('错误对象:', error);
// 返回 true 表示已处理,不再向上抛出
return true;
};
// 触发错误
// window.onerror 会被调用
|
unhandledrejection:未处理的 Promise rejection
1
2
3
4
5
6
7
8
9
10
| // 当 Promise 被 reject 但没有 .catch() 处理时触发
window.addEventListener('unhandledrejection', function(event) {
console.log('未处理的 Promise 错误:');
console.log('错误对象:', event.reason);
// 阻止默认行为(浏览器控制台警告)
event.preventDefault();
});
Promise.reject(new Error('未处理的错误!'));
|
本章小结
本章我们学习了错误处理:
- try…catch:捕获同步代码中的错误。
- Error 对象:包含 message、name、stack 信息。
- 内置错误类型:ReferenceError、TypeError、SyntaxError、RangeError、URIError。
- throw:手动抛出错误。
- 异步错误处理:Promise 用 .catch(),async/await 用 try…catch。
- 全局错误处理:window.onerror 和 unhandledrejection。
错误处理是写出健壮代码的关键。学会优雅地处理错误,你的程序就不会轻易崩溃了。
下一章,我们要学习调试——让 bug 无所遁形!