2023-06-11 17:19:39 +08:00
|
|
|
|
## 前言
|
|
|
|
|
|
|
|
|
|
实际开发中,我们经常会封装一些工具函数,这些函数可能给自己用,也可能给外部团队用。
|
|
|
|
|
|
|
|
|
|
在函数内部,如果不符合预期的业务逻辑,或者遇到异常情况时,很多人的写法是直接 return,不往下执行了。但是 return 的写法存在一个很大的弊端:**调用者不知道是因为函数内部没有正常执行,还是执行的返回结果就是一个undefined**。return 的写法只是退避了问题,没有解决问题。
|
|
|
|
|
|
|
|
|
|
所以,我们需要**处理**异常,即:**抛出**异常,然后**捕获**异常。
|
|
|
|
|
|
|
|
|
|
## 抛出异常
|
|
|
|
|
|
|
|
|
|
我们可以通过 `throw`关键字,抛出一个**用户自定义**的异常。当代码执行时遇到throw 语句时,当前函数会停止停止,即:throw 后面的代码不会再执行。
|
|
|
|
|
|
|
|
|
|
throw 意思是,告诉调用者,当前被调用的函数报错了,调用者需要捕获异常或者修改代码逻辑。
|
|
|
|
|
|
|
|
|
|
### 通过 throw 抛出异常
|
|
|
|
|
|
|
|
|
|
可以在 throw 的后面添加表达式或者数据类型,将添加的内容抛出去。数据类型可以是:number、string、boolean、对象等。
|
|
|
|
|
|
|
|
|
|
代码举例:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
function sum(num1, num2) {
|
|
|
|
|
if (typeof num1 !== "number") {
|
|
|
|
|
throw "type error: num1传入的类型有问题, 必须是number类型"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof num2 !== "number") {
|
|
|
|
|
throw "type error: num2传入的类型有问题, 必须是number类型"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return num1 + num2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sum('a', 'b');
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
打印结果:
|
|
|
|
|
|
|
|
|
|
![image-20230608180755608](https://img.smyhvae.com/image-20230608180755608.png)
|
|
|
|
|
|
|
|
|
|
当然,我们还可以 throw一个封装好的对象。比如:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
class myError {
|
|
|
|
|
constructor(errCode, errMsg) {
|
|
|
|
|
this.errCode = errMsg;
|
|
|
|
|
this.errMsg = errMsg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function foo() {
|
|
|
|
|
throw new myError(-1, 'not login');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foo();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
上面这种写法比较麻烦,一般不这么写。其实,JS中已经内置了 Error 类,专门用于生成错误信息。
|
|
|
|
|
|
|
|
|
|
### Error 类
|
|
|
|
|
|
|
|
|
|
JS内置的 Error 类非常好用。
|
|
|
|
|
|
|
|
|
|
代码举例:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
function foo() {
|
|
|
|
|
throw new Error('not login');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foo();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
打印结果:
|
|
|
|
|
|
|
|
|
|
![image-20230608180103263](https://img.smyhvae.com/image-20230608180103263.png)
|
|
|
|
|
|
|
|
|
|
上面的打印结果可以看到,通过 Error 抛出来的错误,不仅可以看到报错信息,还可以看到调用栈,便于快速定位问题所在。非常方便。
|
|
|
|
|
|
|
|
|
|
## 捕获异常
|
|
|
|
|
|
|
|
|
|
### 不捕获异常会怎么样
|
|
|
|
|
|
|
|
|
|
如果只是抛出异常,而不捕获异常的话,是非常危险的。这意味着后续代码(包括**全局代码**)不会再执行了。因为这个异常信息会层层往上,抛给上层的**调用者**。如果一直未被捕获,则最终会抛给**浏览器**。浏览器控制台就会报错,并不会继续执行后续代码,程序被强行终止。
|
|
|
|
|
|
|
|
|
|
代码举例:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
function foo() {
|
|
|
|
|
throw new Error('not login');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foo();
|
|
|
|
|
// 后续代码不会再执行
|
|
|
|
|
console.log('qianguyihao');
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
打印结果:
|
|
|
|
|
|
|
|
|
|
![image-20230608182003407](https://img.smyhvae.com/image-20230608182003407.png)
|
|
|
|
|
|
|
|
|
|
所以,为了避免上述问题,我们还需要手动捕获异常。我们捕获到异常之后,这个异常就不会继续网上抛了,更不会抛给浏览器。
|
|
|
|
|
|
|
|
|
|
### 通过 try catch 捕获异常
|
|
|
|
|
|
|
|
|
|
我们可以使用 try catch 抛出异常。
|
|
|
|
|
|
|
|
|
|
代码举例:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
function foo() {
|
|
|
|
|
throw new Error('not login');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过 try catch 手动捕获异常
|
|
|
|
|
try {
|
|
|
|
|
foo();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.log(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 后续代码会继续执行
|
|
|
|
|
console.log('qianguyihao');
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
打印结果:
|
|
|
|
|
|
|
|
|
|
![image-20230608182140002](https://img.smyhvae.com/image-20230608182140002.png)
|
|
|
|
|
|
|
|
|
|
### 通过 try catch finally 捕获异常
|
|
|
|
|
|
|
|
|
|
如果有些代码必须要执行,我们可以放到 finally 里。
|
|
|
|
|
|
|
|
|
|
- 不管是否遇到异常,finally的代码一定会执行。
|
|
|
|
|
- 如果 try 和 finally 中都有返回值,那么会使用finally中的返回值。
|
|
|
|
|
|
|
|
|
|
代码举例:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
function foo() {
|
|
|
|
|
throw new Error('not login');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过 try catch 捕获异常
|
|
|
|
|
try {
|
|
|
|
|
foo();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.log(err);
|
|
|
|
|
} finally {
|
|
|
|
|
console.log("finally")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 后续代码会继续执行
|
|
|
|
|
console.log('qianguyihao');
|
|
|
|
|
```
|
|
|
|
|
|
2023-06-12 22:52:35 +08:00
|
|
|
|
## try catch 只能捕获同步代码的异常
|
2023-06-11 17:19:39 +08:00
|
|
|
|
|
2023-06-12 22:52:35 +08:00
|
|
|
|
try catch只能捕获同步代码里的异常,而 Promise.reject() 是异步代码。
|
2023-06-11 17:19:39 +08:00
|
|
|
|
|
2023-06-12 22:52:35 +08:00
|
|
|
|
原因是:当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在 try-catch 所在的栈,所以 try-catch 并不能捕获到错误。对于微任务而言(比如 promise)promise 的构造函数的异常只能被自带的 reject 也就是.catch 函数捕获到。
|
2023-06-11 17:19:39 +08:00
|
|
|
|
|
2023-06-12 22:52:35 +08:00
|
|
|
|
参考链接:
|
|
|
|
|
|
|
|
|
|
- [try-catch 能抛出 promise 的异常吗](https://blog.csdn.net/xiaoluodecai/article/details/107297404)
|
2023-06-11 17:19:39 +08:00
|
|
|
|
|