「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」
作者: Ashish Lahoti 译者:前端很美 来源:codingnconcepts
前言
本文我们将会回顾通过使用try, catch, finally and throw来处理错误, 也会回顾内置的js错误对象(如Error、SyntaxError、ReferenceError 等),以及如何自定义错误。
1.使用 try..catch..finally..throw
在js中我们使用try, catch, finally and throw来处理错误
- 使用
try关键字包裹代码以检查错误。 - 使用
throw关键字用于抛出自定义错误。 - 使用
catch关键字处理捕获的错误。catch代码快对应于try代码块。 - 而
finally代码块则不管是否有异常都会执行。finally块与try和catch块对应。
1.1try
每个try都必须与一个catch or finally代码块对应, 要不然就会报语法错误。以下代码可以证明:
try {
throw new Error('Error while executing the code');
}
ⓧ Uncaught SyntaxError: Missing catch or finally after try
1.2try..catch
使用try和catch是比较优雅的方式,catch将会处理try代码块抛出的错误。
try {
throw new Error('Error while executing the code');
} catch (err) {
console.error(err.message);
}
➤ ⓧ Error while executing the code
1.2.1try..catch 和无效代码
try..catch 无法捕获无效代码引起的异常,如下代码,try代码块里面的有语法错误的代码引起的异常无法被catch所捕获
try {
~!$%^&*
} catch(err) {
console.log("code execution will never reach here");
}
➤ ⓧ Uncaught SyntaxError: Invalid or unexpected token
1.2.2try..catch 和异步代码
类似于上面,try..catch没有办法捕获由随后执行的异步代码引起的异常。
try {
setTimeout(function() {
noSuchVariable; // undefined variable
}, 1000);
} catch (err) {
console.log("code execution will never reach here");
}
1秒后未捕获的异常将会抛出
➤ ⓧ Uncaught ReferenceError: noSuchVariable is not definedn
优雅的处理方式是,把try..catch放到异步代码内来处理异常。
setTimeout(function() {
try {
noSuchVariable;
} catch(err) {
console.log("error is caught here!");
}
}, 1000);
1.2.3 嵌套的 try..catch
我们可以使用嵌套的try..catch来向上抛异常。
try {
try {
throw new Error('Error while executing the inner code');
} catch (err) {
throw err;
}
} catch (err) {
console.log("Error caught by outer block:");
console.error(err.message);
}
Error caught by outer block:
➤ ⓧ Error while executing the code
1.3try..finally语句
不推荐, 只使用try..finally,而不使用catch ,来看看下面的代码会导致什么问题。
try {
throw new Error('Error while executing the code');
} finally {
console.log('finally');
}
finally
➤ ⓧ Uncaught Error: Error while executing the code
我们至少需要注意两件事情:
- 即使try抛出了异常,finally块的代码也会执行
- 因为
catch块抛出的异常没有优雅的被捕获,将会导致 Uncaught Error
1.4try..catch..finally
建议将 try 与 catch 块和可选的 finally 块一起使用。
try {
console.log("Start of try block");
throw new Error('Error while executing the code');
console.log("End of try block -- never reached");
} catch (err) {
console.error(err.message);
} finally {
console.log('Finally block always run');
}
console.log("Code execution outside try-catch-finally block continue..");
Start of try block
➤ ⓧ Error while executing the code
Finally block always run
Code execution outside try-catch-finally block continue..
这里我们需要看到三点:
try块抛出异常后的代码不会被执行。- 这次异常被
catch优雅的处理了 - 即使在 try 块抛出异常后, finally块也会执行。
finally 块通常用于清理资源或关闭流,如下所示:
try {
openFile(file);
readFile(file);
} catch (err) {
console.error(err.message);
} finally {
closeFile(file);
}
1.5throw
throw 语句用于抛出异常。
throw <expression>
// throw primitives and functions
throw "Error404";
throw 42;
throw true;
throw {toString: function() { return "I'm an object!"; } };
// throw error object
throw new Error('Error while executing the code');
throw new SyntaxError('Something is wrong with the syntax');
throw new ReferenceError('Oops..Wrong reference');
// throw custom error object
function ValidationError(message) {
this.message = message;
this.name = 'ValidationError';
}
throw new ValidationError('Value too high');
2.异步代码中的错误处理
建议对异步代码(如API调用)使用 Promises 和 async await,因为它们提供了对错误处理方法。
2.1then..catch 和 Promises
我们可以使用then() 和 catch()来处理Promise链中的异常。如下代码:
Promise.resolve(1)
.then(res => {
console.log(res); // 打印'1'
throw new Error('something went wrong'); // throw error
return Promise.resolve(2); // 这里不会执行
})
.then(res => {
//这里的代码不会被执行,因为上个块有异常抛出导致promise没有resolved
console.log(res);
})
.catch(err => {
console.error(err.message); // 打印 'something went wrong'
return Promise.resolve(3);
})
.then(res => {
console.log(res); // 打印 '3'
})
.catch(err => {
//代码不会被执行因为promise已经在上个块resoved了
console.error(err);
})
来看一个更实际的例子,这里使用 fetch 调用 API,它返回一个 promise 对象。 我们使用 catch 块优雅地处理 API错误。
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
fetch("http://httpstat.us/500")
.then(handleErrors)
.then(response => console.log("ok"))
.catch(error => console.log("Caught", error));
Caught Error: Internal Server Error
at handleErrors (<anonymous>:3:15)
2.2try..catch 和 async await
使用async await处理异步代码,这时使用try..catch将会变得非常简单,如下所示:
(async function() {
try {
await fetch("http://httpstat.us/500");
} catch (err) {
console.error(err.message);
}
})();
再来看一个使用fetch调用api,这将返回一个promise对象,通过使用try..catch我们可以很优雅的处理api异常。
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
}
(async function() {
try {
let response = await fetch("http://httpstat.us/500");
handleErrors(response);
let data = await response.json();
return data;
} catch (error) {
console.log("Caught", error)
}
})();
Caught Error: Internal Server Error
at handleErrors (<anonymous>:3:15)
at <anonymous>:11:7