无需try catch如何实现JavaScript全局错误捕获
你之前使用window.onerror仅返回"Script error."、行号列号为0的问题,除了跨源脚本的同源策略限制,还有一个核心原因:window.onerror仅在事件冒泡阶段触发,LWC的Shadow DOM隔离边界会阻断错误事件冒泡到window对象,因此无法拿到组件内部的完整错误信息。
不需要给每个组件的代码单独包裹try/catch,以下方案组合使用可以覆盖绝大多数前端错误场景:
1. 用捕获阶段的全局error事件替代window.onerror
该方案可以覆盖所有同步运行时错误、静态资源(脚本/图片/样式)加载错误,监听注册在事件捕获阶段,不会被Shadow DOM边界拦截。
在应用最顶部的初始化入口(必须在所有业务组件加载前执行)注册监听:
window.addEventListener('error', (event) => { event.preventDefault(); const errorLog = { message: event.message, source: event.filename, line: event.lineno, column: event.colno, stack: event.error?.stack || '', errorType: 'runtime error' }; // 资源加载错误识别 if (event.target && (event.target.src || event.target.href)) { errorLog.resourceUrl = event.target.src || event.target.href; errorLog.errorType = 'resource load error'; } // 替换为自身业务的日志上报逻辑 console.log('全局捕获错误:', errorLog); }, true); // 第三个参数必须传true,开启捕获阶段监听
如果你的应用加载了跨源托管的脚本资源,需要给对应<script>标签添加crossorigin="anonymous"属性,同时静态资源服务配置匹配当前域名的Access-Control-Allow-Origin响应头,才能拿到跨源脚本的完整错误栈,否则浏览器会自动将错误信息脱敏为"Script error."。
2. 注册unhandledrejection事件捕获异步Promise错误
全局error事件无法捕获未处理的Promise rejection,包括async/await抛出的错误、未加catch的fetch/接口请求错误等,需要单独注册监听,同样使用捕获阶段:
window.addEventListener('unhandledrejection', (event) => { event.preventDefault(); const errorLog = { message: typeof event.reason === 'object' ? event.reason.message : String(event.reason), stack: event.reason?.stack || '', errorType: 'unhandled promise rejection' }; // 复用统一的日志上报逻辑 console.log('全局捕获异步错误:', errorLog); }, true);
3. 实现LWC原生全局错误边界
LWC框架本身提供了errorCallback生命周期钩子,专门用于捕获子组件在渲染、生命周期执行、事件回调过程中抛出的错误,不会受Shadow DOM隔离或沙箱限制,拿到的错误栈完全准确。
你只需要实现一个根级错误边界组件,将所有业务组件作为子元素包裹即可:
// globalErrorBoundary.js import { LightningElement } from 'lwc'; export default class GlobalErrorBoundary extends LightningElement { hasRenderError = false; errorDetail = null; // 子组件抛错时框架会自动触发该钩子 errorCallback(error, stackTrace) { this.hasRenderError = true; this.errorDetail = { message: error.message, stack: stackTrace }; // 复用统一日志上报逻辑 console.log('LWC框架捕获组件错误:', this.errorDetail); } }
对应模板文件配置错误降级UI,避免整个应用白屏:
<!-- globalErrorBoundary.html --> <template> <template if:false={hasRenderError}> <slot></slot> <!-- 插槽挂载所有业务路由、业务组件 --> </template> <template if:true={hasRenderError}> <div class="error-container"> 页面加载异常,请刷新后重试 </div> </template> </template>
4. 宏任务API包装补漏
部分LWC运行时(比如Salesforce平台沙箱)会拦截setTimeout、setInterval、requestAnimationFrame等宏任务回调的错误冒泡,导致全局事件监听拿不到对应错误,可以在入口处统一包装这类API,将错误主动抛到全局捕获链路:
// 以setTimeout为例,其余宏任务API逻辑一致 const originSetTimeout = window.setTimeout; window.setTimeout = (cb, delay, ...args) => { return originSetTimeout(() => { try { cb.apply(this, args); } catch (err) { window.dispatchEvent(new ErrorEvent('error', { error: err, message: err.message })); } }, delay); };
注意:如果你的LWC应用运行在Salesforce官方平台沙箱中,window全局事件的监听能力会受平台权限限制,优先使用LWC原生的
errorCallback错误边界作为核心捕获方案,其余方案作为补充。
内容的提问来源于stack exchange,提问作者AdityaHM

