直接写 console.log(e) 等于丢错误,因仅显示[object Error],丢失stack、message及自定义字段,且若不throw或上报,错误将彻底消失;应改用console.error(e)或显式拼接message与stack。

catch 中直接写 console.log(e) 为什么等于丢错误
因为 e 是 Error 实例,console.log(e) 在多数浏览器里只打印 [object Error],丢失 stack、message、甚至自定义字段。更糟的是,如果后续没 throw 或上报,这个错误就彻底消失,线上出问题时查不到源头。
- 用
console.error(e)替代console.log(e)—— 它会自动展开堆栈 - 若必须用
console.log,显式拼接:console.log(`Error: ${e.message}\n${e.stack}`) - Node.js 环境下注意
e.stack可能为undefined(比如throw 'string'),优先用util.format(e)或确保抛出的是Error实例
要不要在 catch 里 throw e 或 throw new Error()
取决于上下文是否还有上层能处理它。盲目 throw e 可能导致未捕获异常崩溃;盲目吞掉又等于埋雷。关键看责任边界:
- 你封装的是工具函数(如
fetchWithTimeout),应包装错误:throw new Error(`Fetch failed: ${e.message}`),并保留原始e.cause = e(ES2022+)或手动挂载e.original = e - 你在业务逻辑层(如 React 组件的
useEffect),通常不该再抛,而是转成用户可读提示 + 上报:reportError(e); setErrorMessage('加载失败,请重试') - 绝对避免
catch { /* 空块 */ }或仅catch { return null }—— 这是静默失败的典型信号
如何让错误信息既完整又不泄露敏感数据
日志和上报时,原始 e.stack 很有用,但可能含路径、变量值、token 片段。不能靠“信任前端不传”来免责。
- 用白名单过滤
Error实例属性:只保留message、name、stack(截断前 20 行)、cause(递归处理) - 对
stack做正则清洗:e.stack.replace(/(Bearer|token|password|secret)[^\s]+/gi, '[REDACTED]') - 服务端错误响应体(如
response.json())要检查error.detail类字段,不直接透出给前端展示或日志
用 try/catch 还是 .catch()?Promise 链里容易漏哪
混用时最容易漏掉异步错误。比如 async function 内部 await fetch().then(...),若 then 回调里抛错,不会被外层 try/catch 捕获,因为已脱离 Promise 链主流程。
- 统一用
await+try/catch,避免在.then()里做可能抛错的操作 - 如果必须用
.then(),末尾加.catch(e => { /* 处理 */ }),且这个catch必须显式上报或 rethrow - 注意
Promise.all([p1, p2])中任一 promise reject 会导致整个 reject,但错误只返回第一个,要用Promise.allSettled获取全部结果再分别判断
错误真正“优雅”的地方不在格式多漂亮,而在于每一条被处理的异常都明确回答了三个问题:它从哪来、现在去哪、谁负责跟进。漏掉任意一个,就不是处理,只是转移。










