前端异步代码里的错误处理,大多数人第一反应还是 try/catch。它能解决问题,但写多了难免觉得啰嗦:嵌套多、逻辑被打断,读起来也不太舒服。
所以这几年,越来越多项目开始尝试别的方式——写法更轻,结构更清晰。
这篇文章就来聊聊三种替代方案:一个语言层的提案,一个可以自己封装的小工具,还有一个现成的社区库。选好用的方式,能让错误处理简单不少。
写 JavaScript 的人都知道,try/catch 虽然是处理异步错误的“正道”,但一旦多起来,整个代码就开始变得臃肿、重复、难读。
你可能见过这种写法:
try {
const data = await fetchUser();
doSomething(data);
} catch (e) {
console.error('出错了', e);
}
写一两个还好,但如果你有十几个异步调用,每个都要包一层 try/catch,不仅烦,而且破坏代码结构。不少人甚至为了偷懒,直接不处理错误或者一把包住:
try {
// 一大堆 await
} catch (e) {
// 一个错误搞不清是哪里来的
}
有没有更好的写法?有,而且不止一种。
一个值得关注的思路来自一个全新的语言提案,它设想在 JavaScript 中引入一种新的 try 表达式语法,它不是语句,而是一个表达式。
提案地址:https://github.com/arthurfiorette/proposal-try-operator
const [ok, err, result] = try await fetchUser();
这个写法的意思很明确:
这样一来,不仅避免了冗长的 try/catch,还天然具备结构化的错误处理方式。
const [ok, err, user] = await safeAwait(fetchUser());
if (!ok) {
console.error('请求失败:', err);
return;
}
console.log('用户数据:', user);
是不是很像 Go 的 val, err := fn(),或者 Rust 的 Result?这就是提案的核心:让错误处理从控制流转向值表达式。
虽然这个提案还在 Stage 1,离真正进入 JavaScript 还有一段距离,但它提出了一种很有前景的思路:
错误不一定要“捕获”,也可以像值一样被“解构”。
语言层还没进化?那我们就自己造个轮子。
一个常见的思路是:将 Promise 的执行结果封装成一个三元组 [ok, err, data],结构明确,逻辑清晰。来看实现:
export type SafeAwaitResult<T> =
| [true, null, T]
| [false, Error, null];
exportasyncfunction safeAwait<T>(promise: Promise<T>): Promise<SafeAwaitResult<T>> {
try {
const result = await promise;
return [true, null, result];
} catch (err: any) {
const error = err instanceofError ? err : newError(String(err));
return [false, error, null];
}
}
使用时非常直观:
const [ok, err, user] = await safeAwait(fetchUser());
if (!ok) {
console.error('请求失败:', err);
return;
}
console.log('用户数据:', user);
这套封装的好处是显而易见的:
而且你还可以链式使用,避免回到嵌套地狱:
const [ok1, err1, user] = await safeAwait(fetchUser());
if (!ok1) return handle(err1);
const [ok2, err2, posts] = await safeAwait(fetchPosts(user.id));
if (!ok2) return handle(err2);
renderDashboard(user, posts);
这种写法非常适合搭配中间件、hooks 或服务层封装,逐渐成为许多项目的标准做法。
如果你不想自己封装,还有一个现成、稳定的库可以用:await-to-js
它的设计初衷和 safeAwait 类似,把 Promise 的结果转成 [error, result] 形式:
npm install await-to-js
使用方法如下:
import to from 'await-to-js';
const [err, data] = await to(fetchUser());
if (err) return handle(err);
render(data);
如果你的项目希望快速接入结构化的错误处理,不妨试试这个库。
try/catch | |||
safeAwait | |||
await-to-js |
在今天,继续用 try/catch 处理每一个异步错误,已经有些过时。无论是语言层面的提案,还是我们可以自己实现的封装,甚至是社区提供的优秀工具,目的都是一样的:让错误处理变得更清晰、更优雅、更现代。
再见了,重复的 try/catch,写更清爽的代码,从现在开始。
来源公众号:前端充电宝
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
vue工程npm run serve/start/dev启动时,node_modules文件报:Cannot read property range of null 错误,该问题是babel-eslint版本更新问题导致的;
在ajax请求后台数据时有时会报 HTTP 400 错误 - 请求无效 (Bad request);出现这个请求无效报错说明请求没有进入到后台服务里;原因:前端提交数据的字段名称或者是字段类型和后台的实体类不一致
我们都知道 try catch 无法捕获 setTimeout 异步任务中的错误,那其中的原因是什么。以及异步代码在 js 中是特别常见的,我们该怎么做才比较?
父页面初始化声明变量a为数组(数组对象是引用类型,赋值传递的是地址),创建iframe子页面后给父页面变量a赋值,赋值后销毁iframe子页面,再次调用变量a的时候就会抛出异常‘SCRIPT5011:不能执行已释放Script的代码’。
js错误的实质,也是发出一个事件,处理他,error实例对象message:错误提示信息,name:错误名称(非标准属性)宿主环境赋予
文件上传的功能时候,调用fs.renameSync方法错误,这个提示是跨区重命名文件出现的权限问题。先从源文件拷贝到另外分区的目标文件,然后再unlink,就可以了。
如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断
现在,有越来越多所谓的“教程”来帮助我们提高网站的易用性。我们收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站。
为什么要做前端错误监控?1. 为了保证产品的质量2. 有些问题只存在于线上特定的环境3. 后端错误有监控,前端错误没有监控,前端错误分为两类: 即时运行错误和资源加载错误
当我们在进行开发的时候,通常需要属于我们自己的错误类来反映任务中可能出现的特殊情况。对于网络操作错误,我们需要 HttpError,对于数据库操作错误,我们需要 DbError,对于搜索操作错误,我们需要 NotFoundError,等等
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!