再见 try/catch,我有更好的选择了!

更新日期: 2025-08-15阅读: 42标签: 错误

前端异步代码里的错误处理,大多数人第一反应还是 try/catch。它能解决问题,但写多了难免觉得啰嗦:嵌套多、逻辑被打断,读起来也不太舒服。

所以这几年,越来越多项目开始尝试别的方式——写法更轻,结构更清晰。

这篇文章就来聊聊三种替代方案:一个语言层的提案,一个可以自己封装的小工具,还有一个现成的社区库。选好用的方式,能让错误处理简单不少。


传统 try/catch 的痛点

写 JavaScript 的人都知道,try/catch 虽然是处理异步错误的“正道”,但一旦多起来,整个代码就开始变得臃肿、重复、难读。

你可能见过这种写法:

try {
  const data = await fetchUser();
  doSomething(data);
catch (e) {
  console.error('出错了', e);
}

写一两个还好,但如果你有十几个异步调用,每个都要包一层 try/catch,不仅烦,而且破坏代码结构。不少人甚至为了偷懒,直接不处理错误或者一把包住:

try {
  // 一大堆 await
catch (e) {
  // 一个错误搞不清是哪里来的
}

有没有更好的写法?有,而且不止一种。


语言层面的尝试:try 操作符提案

一个值得关注的思路来自一个全新的语言提案,它设想在 JavaScript 中引入一种新的 try 表达式语法,它不是语句,而是一个表达式

提案地址:https://github.com/arthurfiorette/proposal-try-operator
const [ok, err, result] = try await fetchUser();

这个写法的意思很明确:

  • 如果成功,ok 是 trueresult 有值;
  • 如果失败,ok 是 falseerr 是错误对象。

这样一来,不仅避免了冗长的 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 还有一段距离,但它提出了一种很有前景的思路:

错误不一定要“捕获”,也可以像值一样被“解构”。

自定义封装:手写一个 safeAwait

语言层还没进化?那我们就自己造个轮子。

一个常见的思路是:将 Promise 的执行结果封装成一个三元组 [ok, err, data],结构明确,逻辑清晰。来看实现:

export type SafeAwaitResult<T> =
  | [truenull, T]
  | [falseErrornull];

exportasyncfunction safeAwait<T>(promise: Promise<T>): Promise<SafeAwaitResult<T>> {
try {
    const result = await promise;
    return [truenull, 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);

这套封装的好处是显而易见的:

  • 语义清晰ok 表示状态,err 和 data 结构稳定
  • 无 try/catch:逻辑更线性,阅读友好
  • 类型明确:配合泛型推导,IDE 提示清晰
  • 易于复用:在整个项目中统一处理异步异常

而且你还可以链式使用,避免回到嵌套地狱:

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 一步到位

如果你不想自己封装,还有一个现成、稳定的库可以用: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,写更清爽的代码,从现在开始。

来源公众号:前端充电宝

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/12884

解决Cannot read property range of null 错误

vue工程npm run serve/start/dev启动时,node_modules文件报:Cannot read property range of null 错误,该问题是babel-eslint版本更新问题导致的;

HTTP 400 错误 - 请求无效 (Bad request)

在ajax请求后台数据时有时会报 HTTP 400 错误 - 请求无效 (Bad request);出现这个请求无效报错说明请求没有进入到后台服务里;原因:前端提交数据的字段名称或者是字段类型和后台的实体类不一致

js异步错误捕获

我们都知道 try catch 无法捕获 setTimeout 异步任务中的错误,那其中的原因是什么。以及异步代码在 js 中是特别常见的,我们该怎么做才比较?

不能执行已释放Script的代码

父页面初始化声明变量a为数组(数组对象是引用类型,赋值传递的是地址),创建iframe子页面后给父页面变量a赋值,赋值后销毁iframe子页面,再次调用变量a的时候就会抛出异常‘SCRIPT5011:不能执行已释放Script的代码’。

JS错误处理:前端JS/Vue/React/Iframe/跨域/Node

js错误的实质,也是发出一个事件,处理他,error实例对象message:错误提示信息,name:错误名称(非标准属性)宿主环境赋予

nodejs提示 cross-device link not permitted, rename 错误解决方法

文件上传的功能时候,调用fs.renameSync方法错误,这个提示是跨区重命名文件出现的权限问题。先从源文件拷贝到另外分区的目标文件,然后再unlink,就可以了。

Js中使用innerHTML的缺点是什么?

如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断

Web前端开发,必须规避的8个错误点!

现在,有越来越多所谓的“教程”来帮助我们提高网站的易用性。我们收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站。

web前端错误监控

为什么要做前端错误监控?1. 为了保证产品的质量2. 有些问题只存在于线上特定的环境3. 后端错误有监控,前端错误没有监控,前端错误分为两类: 即时运行错误和资源加载错误

自定义错误及扩展错误

当我们在进行开发的时候,通常需要属于我们自己的错误类来反映任务中可能出现的特殊情况。对于网络操作错误,我们需要 HttpError,对于数据库操作错误,我们需要 DbError,对于搜索操作错误,我们需要 NotFoundError,等等

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!