稀土掘金技术社区 03月23日
为什么程序员痴迷于错误信息上报?
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了前端错误监控的重要性、核心价值以及实现方法。文章强调了错误监控在提升用户体验、保障系统稳定性和优化开发流程中的关键作用。通过分析常见的错误类型、提供多维度的错误拦截方案,并结合小程序端的实践,为开发者构建完善的错误监控体系提供了指导。

🚨 错误监控的核心价值在于快速响应生产环境错误,提升用户体验。文章强调了白屏时长和接口错误率等指标对用户留存率和转化率的影响,并提出了快速响应错误、减少损失、规范上线流程的黄金时间轴。

🔍 前端错误主要分为显性错误和隐性错误两大类,其中显性错误直接阻断执行,而隐性错误则涉及资源加载和异步异常等。文章详细介绍了语法错误、运行时异常、资源加载失败、Promise穿透和框架特异性错误等五大常见错误类型。

💡 错误信息的设计需要包含足够的上下文,但要避免信息冗余。文章介绍了错误报告的核心字段,如错误标识、类型、消息、堆栈、组件名、环境信息等。同时,还提供了处理不可序列化数据的技巧,确保错误信息能够被完整捕获。

🛡️ 前端错误拦截需要构建多维度防御体系,包括全局捕获、资源监听和代码层try/catch。文章详细介绍了H5和小程序端的错误捕获策略,并强调了全局捕获作为最后一道防线的重要性。

原创 11在上班 2025-03-23 09:00 重庆

点击关注公众号,“技术干货” 及时达!

前言

从上家公司开始,监控就由我们组身强体壮的同事来负责,而我只能开发AdminH5;经过一系列焦虑的面试后,咸鱼翻身,这辈子我也做上监控了。千万不要以为我是因为监控的重要性才这么执着,人往往得不到的东西才是最有吸引力的。

在写这篇文章时,我也在思考,为什么走到哪里都会有一群程序员喜欢封装监控呢?即使换个公司、换个组,依然可能需要有人来迭代监控。嗯,「话不多说,先点关注,正文开始」

错误监控的核心价值

「如果让你封装一个前端监控,你会怎么设计监控的上报优先级?」

对于一个网页来说,能否带给用户好的体验,核心指标就是 「白屏时长」「FMP时长」,这两项指标直接影响用户的 「留存率」「体验」

下面通过数据加强理解:

设想一下,当你访问页面时白屏等待了3秒,并且页面没有骨架屏或者Loading态时,你会不会觉得这个页面挂了?这时候如果我们的监控优先关注的是性能,可能用户已经退出了,我们的上报还没调用到。

在这个白屏等待的过程中,JS Error可能已经打印在控制台了,接口可能已经返回了错误信息,但是程序员却毫无感知。

「优先上报错误信息,本质是为了提升生产环境的错误响应速度、减少生产环境的损失、提高上线流程的规范。以下是错误响应的黄金时间轴:」

时间窗口响应动作业务影响
< 1分钟自动熔断异常接口避免错误扩散
1-5分钟触发告警通知值班人员降低MTTR(平均修复时间)
>5分钟生成故障诊断报告优化事后复盘流程

重要章节

错误类型,你需要关注的五大场景

「技术本质」:任何错误收集系统都需要先明确错误边界。前端错误主要分为两类: 显性错误(直接阻断执行)和 隐性错误(资源加载、异步异常等)。


// 显性错误(同步执行阶段) function criticalFunction() { undefinedVariable.access(); // ReferenceError }
// 隐性错误(异步场景) fetchData().then(() => { invalidJSON.parse(); // 异步代码中的错误 });

「关键分类」:通过错误本质将前端常见错误分为5种类型,图示如下。

    「语法层错误」(SyntaxError)
    「ESLint」 可拦截,但运行时需注意动态语法(如 eval,这个用法不推荐)。

    「运行时异常」
    错误的时机场景大部分是在页面渲染完成后,用户对页面发生交互行为,触发JS执行异常。以下是模拟报错的一个例子,用于学习。// 典型场景element.addEventListener('click', () => {throw new Error('Event handler crash');});

    「资源加载失败」
    常见的资源比如图片、JS脚本、字体文件、外链引入的三方依赖等。我们可以通过全局监听处理,比如使用document.addEventListener('error', handler, true)来捕获资源加载失败的情况。但需要注意以下几点:

      <img><script> 等标签的 onerror ,可能会因为事件冒泡机制导致重复收集,比如:

  <!---->
<!-- 局部处理 --> <img src="invalid.jpg" onerror="handleImageError()">
<script> // 全局监听 document.addEventListener('error', (e) => { reportError(e.target); // 全局上报 }, true); </script>

「问题」

    「动态资源的监听失效」,通过 JavaScript 「动态创建」 的资源元素(如 <img><script>),若未显式绑定 onerror,可能无法被全局监听捕获。

  <!---->
// 动态加载图片 const img = new Image(); img.src = 'dynamic.jpg'; document.body.appendChild(img);
// 全局监听可能无法捕获动态资源的错误(取决于浏览器实现)

「原因」

    「Promise 穿透」
    这个问题大部分都是编程不规范导致的,常见写法如:

  // 1. 没有使用.catch捕获Promise的异常情况        // 2. Promise        new Promise(resolve, reject).then(res => {        })

未处理的 rejection 需要通过事件监听来捕获:

 // 现代浏览器已默认报告未处理的 rejection        window.addEventListener('unhandledrejection', e => {          e.preventDefault(); // 阻止默认打印          report(e.reason);        });

    「框架特异性错误」
    Vue/React 等框架的错误边界方案:

 // Vue 3 组合式 API 错误处理        app.config.errorHandler = (err, instance, info) => {          sendError({ ...err, component: instance?.$options.name });        }

错误数据,不只是 stack trace

「信息设计哲学」:错误信息需要包含足够上下文,但需避免信息冗余。首先我们可以分析一下异常事件里有哪些核心字段, 比如常见的JS Error,以下图为例:

 interface ErrorReport {      // 错误标识      fingerprint: string; // 通过 message + stack 生成 hash      type: 'JS_ERROR' | 'RESOURCE' | 'PROMISE' | 'CUSTOM';
// 核心信息 message: string; stack?: string; // 注意 iOS 设备上的 stack 差异 component?: string; // Vue/React 组件名
// 环境信息 meta: { userAgent: string; url: string; timestamp: number; sdkVersion: string; };
// 自定义扩展 extras?: Record<string, any>; // 业务自

定义字段}

「序列化技巧」:处理不可序列化数据(如循环引用)

 function safeStringify(obj) {      const seen = new WeakSet();      return JSON.stringify(obj, (k, v) => {        if (typeof v === 'object' && v !== null) {          if (seen.has(v)) return '[Circular]';          seen.add(v);        }        return v;      });    }

错误拦截,多维度防御体系

H5的三层捕获

    「全局捕获」(最后防线)


window.onerror = (msg, source, lineno, colno, error) => { report({ message: error?.message ?? msg, stack: error?.stack || `${source}:${lineno}:${colno}` }); return true; // 阻止默认控制台打印 };

    「资源监听」(需注意事件捕获阶段)

  document.addEventListener('error', e => {          if (e.target.tagName === 'IMG') {            trackResourceError(e.target.src);          }        }, true); // 使用捕获阶段确保触发

    「代码层 Try/Catch」
    建议在关键业务逻辑手动包裹:

 function wrappedFetch(url) {          try {            return fetch(url).catch(handleFetchError);          } catch (e) {            handleSyncError(e);          }        }

小程序的双端策略

    全局错误捕获

<!---->
// 1. APP级捕获 App({ onError(error) { wx.request({ url: 'https://log.example.com', data: { error: error.message } }); } });
// 2. 页面级错误(Page.onError) Page({ onError(msg) { trackPageError(this.route, msg); } });

2.  API错误处理这种拦截的方式处理小程序原生API,避免了更改业务逻辑,在独立封装成一个sdk时更具备通用性。

<!---->
const originRequest = wx.request; wx.request = function(config) { const { fail } = config; config.fail = function(err) { reportApiError(err); fail?.call(this, err); }; return originRequest(config); };

总结

「一起回顾错误监控的四大核心价值:」

    「生产环境感知器」
    通过错误率、白屏时长等硬指标,量化用户体验和系统健康度,使不可见的代码问题转化为可观测的数据流。

    「故障止损黄金通道」
    建立错误信息→告警响应→热修复的快速闭环,将MTTR(平均修复时间)从小时级压缩至分钟级,如:

    错误上报触发自动熔断机制,10秒内阻断错误扩散

    「技术演进指南针」
    高频错误类型(如资源加载失败率上升)驱动架构优化,推动从「事件驱动开发」到「数据驱动迭代」的范式转变。

    「团队协作润滑剂」
    标准化的错误元数据(组件栈、用户轨迹)打破前后端协作壁垒,使问题定位效率提升60%以上。

当错误监控从 「防御工具」 进化为「业务洞察系统」时,程序员对错误上报的执着,本质上是对 「确定性」 的技术追求——在混沌的软件世界中建立秩序,在脆弱的数字生态里守护体验。这或许正是工程师文化最诗意的表达:用严谨的逻辑对抗无常,以持续观测抵达信任。

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

前端监控 错误拦截 错误处理 前端开发 性能优化
相关文章