当前位置: 首页 > news >正文

Web前端入门:JavaScript 哪些地方需要 try...catch 异常捕获

前端开发一直有种错觉,好像异常捕获都是后端的事,毕竟后端开发时如果不处理代码中的异常,有些资源得不到释放,极其容易导致内存泄漏。

前端由于 JS 的垃圾回收机制无需手动释放资源,反而不会怎么使用异常捕获代码中的错误。实际上任何编程语言,要写出一个健壮性的代码,都需要考虑异常处理。

本文分析下哪些地方可能需要使用异常捕获~~

为什么需要 try...catch

看一个例子:

(() => {function init() {a()b()c()}function a() {console.log('a 方法执行')// 在执行 a 方法时候,代码有异常错误JSON.parse('{a:1}')}function b() {console.log('b 方法执行')}function c() {console.log('c 方法执行')}init()
})()

以上代码在 init 函数中执行了多个方法,但 a 方法在执行后,由于 JSON.parse 格式化的数据有问题会代码报错,从而导致 b 和 c 方法无法执行。

而预期的执行逻辑是 a 方法执行完毕后,继续执行 b 和 c 方法。实际结果:

80-1

b 和 c 方法都未执行,而且用户也无法感知到任何异常,如果此方法放在了一个点击交互中,就会出现点击后没任何反馈,这肯定不是产品要的需求效果!!

稍稍优化:

(() => {function init() {a()b()c()}function a() {console.log('a 方法执行')try {// 在执行 a 方法时候,代码有异常错误JSON.parse('{a:1}')} catch (error) {// 给出用户提示alert('程序异常,请联系管理员')throw new Error('JSON.parse 错误')// 或直接使用 throw error 抛出}}function b() {console.log('b 方法执行')}function c() {console.log('c 方法执行')}init()
})()

优化后虽然代码还是无法执行 b 和 c 方法,但用户会感知到异常错误,对用户来说,至少有了一个交互反馈。

如果逻辑上 a 和 b、c 方法没有关联,那么 a 方法可以不用 throw 抛出错误,直接 return 即可,这样可以保证 b 和 c 方法顺利执行,比如:

function a() {console.log('a 方法执行')try {// 在执行 a 方法时候,代码有异常错误JSON.parse('{a:1}')} catch (error) {// 给出用户提示alert('程序异常,请联系管理员')return false}
}

使用 try...catch

那么在 JS 中有哪些地方需要异常捕获呢??接下来看看各种场景~~

同步代码

这类问题通常用于输入与预期不匹配,导致代码运行错误,如果不处理异常,可能会导致大面积的页面白屏或者没有任何反馈。

比如上面例子中的 JSON.parse() 格式化 JSON 数据时候,正确示例:

try {JSON.parse(jsonString)
} catch (error) {// 根据需要处理错误
}

async/await 的异步代码

如果 await 等待的 Promise 被 reject,那么代码也会抛出异常,如果不处理错误,也会出现没有交互反馈的样子。

网络请求是最常见的 await 错误,正确示例:

async function getData() {try {const res = await fetch('https://test.com/api')const data = await res.json()} catch (error) {// 根据需要处理错误}
}

访问不确定的属性或方法

这种情况通常是在访问后端返回数据的时候会出现异常,比如预期我们需要的是 string 类型,但后端返回的是 null,在针对 string 操作时候,就会导致代码异常。

正确示例:

function getUsers(res) {try {// res 是后端返回的数据const users = res.list.split(',')return users} catch (error) {// 根据需要处理错误}return []
}
getUsers({list: null})

或者使用 JS 提供的 可选链操作符 优化:

function getUsers(res) {// res 是后端返回的数据return res?.list?.split(',') ?? []
}

执行三方代码

三方代码不确定性太大,在执行三方代码提供的 API 尤其需要注意异常处理。

正确示例:

<script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.0/vconsole.min.js"></script>
<script>try {// 如果的 src 引入的 JS 出现网络问题,那么 `new VConsole()` 执行就会报错new VConsole()} catch (error) {// 根据需要处理错误}// ... 后续的代码逻辑
</script>

浏览器的 API 调用

浏览器提供的 API 也不全是能调用的,如果有版本兼容问题,在执行时候,代码也会出现异常错误。

以 localStorage 为例,如果用户禁用了本地存储,就有可能导致方法报错。记得 无痕模式 刚开始兴起那会儿,在无痕模式下访问本地存储就会报错!!

正确示例:

try {localStorage.setItem('name', '前端路引');
} catch (error) {// 根据需要处理错误
}

nodejs 文件操作

在服务端运行 nodejs 读取文件时候,尤其需要小心文件不存在时的异常问题。

正确示例:

try {const content = fs.readFileSync('web3dev.txt', 'utf8');
} catch (error) {// 根据需要处理错误
}

用户输入校验

这种情况一般用于优化代码结构,直接在校验失败时候抛出异常,使用异常捕获统一处理提示信息。

正确示例:

function validateInput(input) {if (!input) {throw new Error('输入不能为空');}return true;
}
function isPhoneNumber(phone) {if (/^1[3456789]\d{9}$/.test(phone)) {return true;}throw new Error('请输入正确的手机号码');
}try {const str = '123456789'validateInput(str);isPhoneNumber(str);// ... 后续的代码逻辑
} catch (error) {alert(error.message);// 根据需要处理错误
}

try...catch 其他用法

try 的用法除了最常见的 try...catch 写法外,还有一些其他写法,比如:

省略 error

try {JSON.parse('{a:1}')
} catch {// 根据需要处理错误
}

使用 finally

无论 try 或 catch 的代码中是否报错,也无论是否有 return 和 throw 关键字。finally 的代码块都会正常执行,常用于资源释放,比如关闭文件流、处理数据库连接、关闭页面 loading 等。

function init() {try {console.log(1)JSON.parse('{a:1}')} catch {console.log(2)// 根据需要处理错误return false} finally {console.log(3)}
}
init()

执行顺序:

1
2
3

省略 catch

虽然 catch 可以省略,但缺少了 catch 捕获异常之后,代码不会往下执行,finally 的代码块不影响,比如:

try {JSON.parse('{a:1}')
} finally {// 根据需要处理错误console.log(1)
}
console.log(2)

执行结果:

80-2

catch 和 finally 两个至少要有一个,否则代码报错。

异步任务异常错误

try...catch 无法捕获异步任务中的异常错误,比如 Promise 中的异常错误,必须使用 Promise.catch 来捕获;setTimeout 的内部异常也无法使用 try 处理。

try {new Promise((resolve, reject) => {throw new Error("测试错误");}).catch((err) => {// 这里代码会执行console.log('Promise 内部错误', err);})
} catch {console.log('不会执行')
}
try {setTimeout(() => {throw new Error("测试错误");}, 100);
} catch {console.log('不会执行')
}

写在最后

任何事物都是犹过不及,合理使用 try...catch 可以有效提高代码健壮性,但过渡使用也容易造成代码冗余,所以编码也需要考虑分寸,拿捏得合适,则是优雅舞者。

编码注意:不要静默吞掉错误,至少使用 console 记录错误信息(如 console.error),否则会影响程序问题排查。

文章转载自:前端路引

原文链接:Web前端入门第 80 问:JavaScript 哪些地方需要 try...catch 异常捕获 - 前端路引 - 博客园

体验地址:JNPF快速开发平台

http://www.dtcms.com/a/295212.html

相关文章:

  • 【图论】倍增与lca
  • Avalonia 基于MVVM的时间统计/系统时间显示 示例
  • EPSON爱普生全系列废墨垫已满清零工具分享附教程下载
  • EasyExcel 模板导出数据 + 自定义策略(合并单元格)
  • 基于深度学习的胸部 X 光图像肺炎分类系统(三)
  • Turbo Intruder 并发插件无法试用--更换新版Burpsuit解决(简单解决安装、破解问题)
  • 开源Qwen凌晨暴击闭源Claude!刷新AI编程SOTA,支持1M上下文
  • 跨境支付入门~国际支付结算(结算篇)
  • AtCoder Beginner Contest 415(ABCDE)
  • `neutron router-gateway-set` 操作失败的可能原因及解决方案
  • 深度分析Java多线程机制
  • 【智能协同云图库】智能协同云图库第六弹:空间模块开发
  • 微服务的编程测评系统6-管理员登录前端-前端路由优化
  • 【开源】WPF的数据可视化大屏解决方案——WpfMap
  • 洛谷 P11378 [GESP202412 七级] 燃烧-普及/提高-
  • fdbus4.2 timer的使用
  • AI时代,我的编程工作搭子
  • ospf单区域实验
  • Windows批量工具,直接起飞!
  • 外部存档(External Archive)机制
  • MNIST 手写数字识别模型分析
  • 无人机电池通讯接口应用:CANFD工业级芯片的选型与技术要点
  • 跨境支付入门~国际支付结算(稳定币)
  • 事务的特性 - ACID
  • 游戏装备被盗,运营商赔不赔
  • 算法牢笼与思想飞地:在人工智能时代守卫灵魂的疆域
  • gig-gitignore工具实战开发(二):设计多源模板系统
  • Python--Tkinter--标准 GUI 工具包
  • 常用的Typescript特性
  • Python进阶知识之pandas库