JavaScript 异常处理
try…catch…finally
捕获并处理异常。支持嵌套。
function test(){
try {
// throw true;
throw 9527;
// throw '我是一个字符串';
// throw new Error('一个异常');
}
catch (e) {
if(typeof e === 'boolean'){
console.error("catch 到 boolean:", e);
}
if(typeof e === 'number'){
console.error("catch 到 number:", e);
}
if(typeof e === 'string'){
console.error("catch 到 string:", e);
}
if (e instanceof Error) {
console.error("catch 到:", e.message);
}
}
finally {
console.log("finally 块始终触发");
}
}
throw
- throw 可以直接抛基础类型,也可以抛对象。
- 有需要的话可以自定义异常类型,默认JS也带了一些
异步中的异常问题
- 同步代码
try catch
无法捕获异步方法中抛出的异常。包括Promise.reject
。
try{
Promise.reject('失败');
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// Promise {<rejected>: '失败'}
// Uncaught (in promise) 失败
try{
Promise.resolve('成功').then(data => {
throw new Error(`你${
data}个鸡儿!`);});
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// Promise {<rejected>: Error: 你成功个鸡儿!
// Uncaught (in promise) Error: 你成功个鸡儿!
- 异步的异常要用链式的
.catch
捕获。它是then(undefined, 拒绝(data))
的简写。
try{
Promise.reject('失败').catch(err=>console.log(`异步的.catch 捕获:${
err}`));
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// 异步的.catch 捕获:失败
try{
Promise.resolve('成功')
.then(data => {
throw new Error(`你${
data}个鸡儿!`);})
.catch(err=>console.log(`异步的.catch 捕获:${
err}`));
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// 异步的.catch 捕获:Error: 你成功个鸡儿!
- 可以使用
async...await
配合Promise
转成同步执行,实现try catch
捕获。但前提是没有被链式.catch
截胡。
try{
await Promise.reject('失败');
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// try catch 捕获:失败
try{
await Promise.resolve('成功')
.then(data => {
throw new Error(`你${
data}个鸡儿!`);});
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// try catch 捕获:Error: 你成功个鸡儿!
下面这个就是被 .catch
截胡了。
try{
await Promise.reject('失败').catch(err=>console.log(`异步的.catch 捕获:${
err}`));
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// 异步的.catch 捕获:失败
当然 .catch
中也可以继续抛。这样外面 try catch
就又能捕获了。
try{
await Promise.reject('失败')
.catch(err=>{
console.log(`异步的.catch 捕获:${
err}`);
throw '异步 .catch 继续抛的异常';
});
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// 异步的.catch 捕获:失败
// try catch 捕获:异步 .catch 继续抛的异常
话说回来,如果再链一个 .catch
就又截胡了。。。
try{
await Promise.reject('失败')
.catch(err=>{
console.log(`异步的.catch 捕获:${
err}`);
throw '异步 .catch 继续抛的异常';
})
.catch(err=>{
console.log(`第二个异步.catch 截胡:${
err}`);
});
}catch(err){
console.error(`try catch 捕获:${
err}`);
}
// 异步的.catch 捕获:失败
// 第二个异步.catch 截胡:异步 .catch 继续抛的异常
函数嵌套调动时的 then、catch
- 多个函数嵌套调用形成的
Promise
链。
可以成一个链看待,那么走 then 还是走 catch 的逻辑就清晰了。(脑补在调用子函数的位子把它包含的 then、catch 拼进来) - 因为本质上是一条链,那么 catch 在前面的优先就高。后续是交给 catch 还是让下面的 then 继续,就看你的业务需要了。
function main() {
return Promise.resolve('成功')
.then(data => {
console.log(`1、main 中的第一个 then:${
data}`); // 1 执行
return subFun(data);
})
.then(data => {
console.log(`4、main 中的第二个 then:${
data}`); // 4 执行
return data;
})
.catch(err=>{
// 4.5 跳过
console.log(`main 中的.catch 捕获到:${
err}`) // 此时状态 resolve 这个 catch 被跳过。
return err;
});
}
function subFun(data){
return Promise.resolve('data')
.then(data => {
console.log(`2、subFun 中的第一个 then:${
data}`); // 2 执行
throw `subFun 中抛异常`; // 抛异常,从此走上 reject 之路
})
.then(data => {
// 2.5 跳过
console.log(`subFun 中的第二个 then:${
data}`); // 此时状态 reject 这个 then 被跳过。
return data;
})
.catch(err=>{
console.log(`3、subFun 中的.catch 捕获:${
err}`) // 3 执行
return err; // 捕获异常,回归 resolve 之路
});
}
main()
.then(data => console.log(`5、最后的then:${
data}`) ) // 5 执行
.catch(err => console.error(`最后的catch :${
err}`) ); // 5.5 跳过
1、main 中的第一个 then:成功
2、subFun 中的第一个 then:data
3、subFun 中的.catch 捕获:subFun 中抛异常
4、main 中的第二个 then:subFun 中抛异常
5、最后的then:subFun 中抛异常