注册
web

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')
}
}

结果如下:


image.png


上述案例中,如果请求传入的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("引擎无法理解这段代码,它是无效的");
}

结果如下:


image.png


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')
}

结果如下:


image.png


因为 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')
}


结果如下:
image.png


总结


在使用try...catch...finally的时候,无论是否发生异常(即是否执行了catch块),finally块中的代码总是会被执行,除非在trycatchfinally块中发生了阻止程序继续执行的情况(如Promsie一直处理pending状态)。


如有错误,请指正O^O!


作者:一诺滚雪球
来源:juejin.cn/post/7419524503200677898

0 个评论

要回复文章请先登录注册