js中的finally一定会执行吗?
背景
在我们程序开发中,我们的代码会出现这种或那种的错误,我们使用try...catch
进行捕获。如果需要不管是成功还是失败都需要执行,我们可能需要finally
。
那么有一个问题,无论是否发生错误,在finally
中的代码一定会执行吗?
下面我们看一个案例:
1. 案例
场景:请求一个接口,如果接口没有正确返回,我们使用try...finally
包裹代码,代码如下:
function getMember(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (num === 1) {
resolve(num)
}
if (num === 0) {
reject()
}
}, 2000)
})
}
async function init() {
try {
console.log('打印***start')
await getMember(0)
console.log('打印***end')
} catch (err) {
console.log('打印***err')
} finally {
console.log('打印***finally')
}
}
结果如下:
上述案例中,如果请求传入的num
由另外一个接口返回,num
的值不是0
或者1
,上述的getMember
就一直处于pengding
状态,接下来的finally
也不会执行。
我们也可以这样理解,当在处理Promise
问题时,我们需要确保Promise
始终得到结果,不管是成功还是失败。
上述代码可以完善如下:
function getMember(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (num === 1) {
resolve(num);
} else if (num === 0) {
reject(new Error('Num is 0'));
} else {
// 默认情况,也解决Promise
resolve('Some default value');
}
}, 2000);
});
}
async function init() {
try {
console.log('打印***start');
const result = await getMember(2); // 传递一个非0非1的值
console.log('打印***end', result);
} catch (err) {
console.log('打印***err', err);
} finally {
console.log('打印***finally'); // 这行总是会被执行
}
}
init();
修改后的例子中,无论num
的值是什么,Promise
都会被解决(要么通过resolve
,要么通过reject
),,确保Promise
被正常处理,才能确保finally
执行。
2. try...catch注意点
2.1 仅对运行时的 error 有效
要使得 try...catch
能工作,代码必须是可执行的。换句话说,它必须是有效的 JavaScript 代码。
如果代码包含语法错误,那么 try..catch
将无法正常工作,例如含有不匹配的花括号:
try {
{
{
} catch (err) {
alert("引擎无法理解这段代码,它是无效的");
}
结果如下:
JavaScript 引擎首先会读取代码,然后运行它。在读取阶段发生的错误被称为“解析时间(parse-time)”错误,并且无法恢复(从该代码内部)。这是因为引擎无法理解该代码。
所以,try...catch
只能处理有效代码中出现的错误。这类错误被称为“运行时的错误(runtime errors)”,有时被称为“异常(exceptions)”。
2.2 try...catch
同步执行
如果在定时代码中发生异常,例如在 setTimeout
中,则 try...catch
不会捕获到异常:
try {
setTimeout(function () {
noSuchVariable; // 脚本将在这里停止运行
}, 1000);
} catch (err) {
alert("不工作");
} finally {
console.log('打印***finally')
}
结果如下:
因为 try...catch
包裹了计划要执行的函数,该函数本身要稍后才执行,这时引擎已经离开了 try...catch
结构。
为了捕获到计划的(scheduled)函数中的异常,那么 try...catch
必须在这个函数内:
try {
setTimeout(function () {
try {
noSuchVariable; // 脚本将在这里停止运行
} catch (error) {
console.log(error)
}
}, 1000);
} catch (err) {
alert("不工作");
} finally {
console.log('打印***finally')
}
结果如下:
总结
在使用try...catch...finally
的时候,无论是否发生异常(即是否执行了catch
块),finally
块中的代码总是会被执行,除非在try
、catch
或finally
块中发生了阻止程序继续执行的情况(如Promsie一直处理pending状态)。
如有错误,请指正O^O!
来源:juejin.cn/post/7419524503200677898