悬空 Promise 是什么
悬空 Promise(floating promise)指调用了一个返回 Promise 的函数,却没有 await、没有 then 与 catch,也没有显式标记忽略:异步任务照跑,失败却无人接收,错误被静默吞掉,执行顺序也不再与代码书写顺序一致。TypeScript 项目里由 typescript-eslint 的 no-floating-promises 规则负责拦截。
基本信息
| 问题表现 | Promise 未 await 也未 catch |
|---|---|
| 对应规则 | @typescript-eslint/no-floating-promises |
| 前置条件 | 需要类型信息,必须配置类型感知的 lint |
| 修复方式 | await、显式 void,或统一收集并处理 |
典型使用场景
- 事件回调里调用 async 函数:失败没有 catch,异常消失在控制台之外
- 初始化逻辑漏了 await:后续代码在数据就绪前就开始执行
- 批量任务并发启动:需要用 Promise.all 或 allSettled 统一处理结果
- 确实不关心结果的场景:显式写 void,并加注释说明理由
- 埋点与日志这类火并忘调用:同样要保证失败不会中断主流程
启用与治理顺序
- 先在 CI 打开类型感知的 lint,否则规则不会生效
- 按目录逐步启用,避免一次报出成百上千条
- 为确实要忽略的调用补上 void 与理由注释
- 在统一入口收集未处理的拒绝,避免进程静默退出
对比写法
对比写法
// 不好:失败无人知晓
loadUser();
// 好:显式等待
const user = await loadUser();
// 并发场景统一处理
const results = await Promise.allSettled([loadUser(), loadOrders()]);
// 明确忽略,需在评审中说明理由
void refreshCache();同族规则与拦截范围
| 规则 | 拦截的问题 |
|---|---|
| no-floating-promises | Promise 被创建后无人处理 |
| no-misused-promises | async 函数被放进期望返回 void 的位置 |
| await-thenable | 对非 Promise 值使用 await |
| require-await | async 函数体内没有任何 await |
这条规则依赖类型信息:只做语法层面的检查不会生效,必须把类型感知的 lint 配置接进流水线。
运行时可以监听未处理的拒绝作为兜底,但它只用来发现漏网之鱼,不能替代逐处显式处理。
用 void 批量消除告警:真实存在的并发与错误处理问题会被一起掩盖掉。