JS 中的 finally 语法有什么意义?是否多余?
写在
finally里中的代码,与直接写在try...catch后面到底有什么区别?本文将对此进行详细讲解。
每一个开发者对try...catch语句应该都不会感到陌生,但是finally却不是每一个人都会用到。而且很多时候,无论我们代码写在finally里面还是外面,好像并没有什么太大区别。
比如,我们经常会使用的请求时的 loading 状态,有些人习惯在finally中重置 loading 状态。
示例 1:
let loading = false;
function fetchData() {
loading = true;
try {
await fetch('/api/xxx');
} finally {
// 写在finally中
loading = false;
}
}有些人习惯直接写在try...catch后面。
示例 2:
let loading = false;
function fetchData() {
loading = true;
try {
await fetch('/api/xxx');
} catch {
}
// 写在try...catch后面
loading = false;
}也有部分人甚至会分别在try和catch中各写一遍。
示例 3:
let loading = false;
function fetchData() {
loading = true;
try {
await fetch('/api/xxx');
// try中写
loading = false;
} catch {
// catch中写
loading = false;
}
}但无论哪种写法,对于当前的业务场景来说都是可行的。
因为finally的本意就是:无论try中的代码是否抛出异常,finally里面的代码“始终”都会执行。
那么,直接写在try...catch语句后面的代码又何尝不是这样呢?没有异常时,代码自然是往下执行;有异常时,被catch捕获后,代码也是正常往下执行。
所以,finally的意义到底在哪里?
我们分两个角度来分析:
1️⃣ 示例 1 和示例 3
示例 3中分别在try和catch中都写了重置状态的代码,它是“完全”可以替代示例 1的,尤其是处理更复杂的业务逻辑时,比写在finally中更加灵活。对于示例 3的写法,finally的优势就是:能够减少相同逻辑的代码,同时增加代码的可读性。
所以,示例 3可以看作是“原始的、粗暴的”写法,finally的出现简化了这种写法,同时让代码变得更优雅了。
当然,一些“特殊的”场景,finally也并不完全适用,还是需要根据具体场景具体分析。
2️⃣ 示例 1 和示例 2
示例 2将重置状态的代码放在了try...catch后面,虽然在示例中的最终效果是相同的,但示例 2的写法并不足够“安全”。
为什么说不足够“安全”?
因为try...catch后面的代码并不能保证“始终”会执行!它其实是与finally的定义是有所区别的,finally中的代码无论如何一定会执行。
比如这种情况:
function foo() {
try {
return 1;
} finally {
return 2;
}
}
function bar() {
try {
return 1;
} catch {}
return 2;
}
foo();
bar();分析一下,foo()和bar()分别会返回什么?
如果你认真了解过finally,你就会知道: foo()会返回2,bar()会返回1。
从代码可以看出,foo()其实是有点反直觉的,明明在try中就已经return 1了,为什么最终返回的却是finally中的return 2呢?
但这也是合理的,还记得之前对finally的定义吗?finally中的代码“始终”都会执行!哪怕函数已经提前return了!这就是finally的绝对安全性。
除了
return,throw、break、continue都不能阻碍finally中语句的执行。
回到示例 2,如果在try中就提前return了,那么后面的重置代码将永远不会被执行。
let loading = false;
function fetchData() {
loading = true;
try {
await fetch('/api/xxx');
return; // 提前返回
} catch {
}
// 写在try...catch后面 --- 永远不会被执行
loading = false;
}对于finally语句的意义,用自己的语言来一个小小的总结:
- 减少相同逻辑代码
- 使用更明确的语义化提高了代码的可读性
- 保证“始终”要执行的代码的安全性
所以,finally只是 JS 给你提供的一个语法,用与不用都取决于你;没有必须使用它的场景,但也绝不是“多余”,它能够让你写代码时多一个更优的选择。