eslint 不强制每个 await 必须包裹在 try-catch 中,真正需防范的是未处理的 promise 拒绝风险;应优先使用 @typescript-eslint/no-floating-promises、no-misused-promises 和 eslint-plugin-ai-guard/strict 等精准规则,并通过响应拦截器和 saferequest 封装实现可控错误处理。

ESLint 本身不提供“强制要求每个 await 都必须包裹在 try-catch 中”的规则——这不是它的设计目标,也不符合 JavaScript 异步编程的实际工程实践。强行对每个 await 加 try-catch 反而会掩盖错误传播意图、增加冗余代码、破坏 Promise 链式处理逻辑。真正需要拦截的,是那些 被忽略的、未被处理的 Promise 拒绝风险,而不是 await 语法本身。
盯住真正危险的异步漏洞,而非语法位置
关键不是“有没有 try-catch”,而是“错误是否被静默吞掉”或“Promise 是否悬空”。ESLint 提供了成熟、精准的规则来捕获这些实际风险:
-
@typescript-eslint/no-floating-promises:强制所有 Promise 必须被 await、.then() 或 .catch() 显式消费。未处理的 Promise(比如只写了
api.fetch()却没接任何链式操作)会直接报错。 -
@typescript-eslint/no-misused-promises:防止把 Promise 当作布尔值或函数参数误用(如
if (fetchUser()) { ... }),这类写法根本不会等待结果,极易引发逻辑错乱。 -
eslint-plugin-ai-guard 的 strict 预设:当启用
strict模式时,它会对空 catch 块(catch (e) {})、仅 console.log 后 re-throw 的 catch、以及未处理的网络请求错误等高危模式标为 error,比机械检查 try-catch 出现次数更有效。
用拦截器 + 安全封装替代满屏 try-catch
与其在业务层堆砌 try-catch,不如统一收口错误处理。例如:
- 在 Axios 响应拦截器中统一判断 status/code,失败时
return Promise.reject(...),让错误自然冒泡; - 提供一个轻量
safeRequest(promise)工具函数,返回[error, data]元组,业务代码用解构即可无痛分支处理,完全规避 try-catch 语法; - 配合
@typescript-eslint/no-floating-promises,确保每个safeRequest(...)调用都被解构或 await,从源头堵住漏网之鱼。
如果真要限制裸 await,需自定义规则(不推荐)
技术上可通过 ESLint 自定义规则遍历 AST,检测顶层 await 表达式是否位于 try/catch 内部。但这样做问题明显:
- 无法区分上下文:顶层模块级 await、组件 setup 中的 await、工具函数内的 await,风险等级完全不同;
- 破坏可读性:为满足规则硬加空 catch 或无意义 .catch(() => {}),反而掩盖真实错误意图;
- 与现代实践冲突:Suspense、React Server Components、Top-level await 等场景天然不需要手动 try-catch。
真正的防线不在语法形式,而在错误是否可见、是否可控、是否可追溯。聚焦 no-floating-promises 和 ai-guard/strict,配合响应拦截与安全封装,才能既守住质量底线,又保持代码简洁与可维护性。











