公司动态
H5 白屏监控实战:window.onerror、关键元素与多信号状态机
window.onerror没有上报不等于用户看到了正常页面。脚本可以不报错但接口一直挂起、关键组件没有挂载或者 WebView 只剩一张空背景反过来页面也可能抛出一个非关键异常但主要内容仍然可见、可操作。因此白屏不是某一种 JavaScript 异常而是“用户在一段时间内没有看到有效内容”的可用性问题。本文把视觉空白、关键元素、错误事件和时间阈值合并成一个确定性分类器并用 7 项本地测试验证confirmed、suspected、recovered、excluded、healthy五种结果。一、错误事件和白屏不是同一个集合浏览器错误信号、性能信号和视觉结果回答的是不同问题。把任何一个信号当成白屏真相都会制造盲区。信号能回答什么单独使用的盲区error同步脚本错误、部分资源加载失败没报错也可能没有有效内容unhandledrejection未处理的 Promise 拒绝不代表主页面一定不可用PerformanceObserver性能时间线中的指定事件有绘制不等于业务内容可用关键元素业务主体是否已经出现选择器失效会造成误判视觉空白用户画面是否长期接近空白大面积留白、骨架屏可能误报MDN 对error的说明明确区分了同步脚本错误与未处理 Promise后者会触发unhandledrejection。这已经说明“只接一个window.onerror”连异常面都覆盖不全更不用说没有异常但内容始终未出现的白屏。二、把布尔告警改成五种结果生产监控最好不要只输出isBlank: true/false。同样是“超过阈值仍空白”是否存在导航失败、是否最终恢复、是否属于已知过渡页处理方式完全不同。状态最小判定推荐动作confirmed视觉空白超阈值、关键元素未出现并有终止性错误立即告警关联版本与错误证据suspected只有单一异常信号或证据尚不完整采样保留等待更多信号或人工复核recovered曾经超阈值空白但关键元素随后出现统计恢复耗时排查慢启动excluded命中已知过渡页、测试页或白底设计页不计入主指标但记录排除规则版本healthy关键元素在阈值内出现且没有终止性错误进入正常性能统计这里的五类是本文的工程建模不是浏览器标准。它的价值在于让告警、发布门禁和排障动作对应到可解释证据而不是把所有异常压成一个数字。三、视觉检测解决“代码根本没跑”的盲区经过脱敏整理的一份历史 WebView APM 资料采用过端侧截图分析容器启动后周期采样画面根据像素纯度判断有效内容是否出现。历史方案记录了 100ms 采样、Android 95%、iOS 98%、超过 5 秒判白屏、最长 10 秒等参数。这些数字只属于当时的设备、页面和容器条件不能直接复制到新项目。新系统至少要重新验证深色模式、骨架屏、大面积留白页面、Canvas/视频、采样开销和隐私边界。端侧最好只计算特征并立即释放位图不保存或上传完整截图。四、浏览器侧要收集互补信号浏览器侧可以把同步错误、资源失败和未处理 Promise 分开采集再由业务代码明确标记关键内容是否就绪。资源错误通常需要在捕获阶段监听避免只盯着window.onerror的五参数回调。window.addEventListener(error,(event){consttargetevent.targetconstisResourcetargetinstanceofHTMLScriptElement||targetinstanceofHTMLLinkElement||targetinstanceofHTMLImageElementreportSignal(isResource?resource_error:script_error)},true)window.addEventListener(unhandledrejection,(){reportSignal(unhandled_rejection)})PerformanceObserver可以观测受支持的性能条目但它是性能时间线入口不是白屏裁判。生产代码应先检查PerformanceObserver.supportedEntryTypes并把“首次绘制”“关键元素出现”“业务可交互”保留为不同时间点。五、先统一事件再做确定性分类各端信号最终应归一成一个不含截图和敏感信息的观察对象。算法版本、阈值和排除规则必须进入事件否则阈值调整前后的白屏率无法直接比较。constobservation{route:/checkout,visualBlankMs:6200,thresholdMs:5000,keyElementSeen:false,terminalError:true,excluded:false,algorithmVersion:visual-v3signals-v1,}terminalError不应等于“出现任意 JS 错误”。它应由导航失败、主文档 HTTP 失败、关键资源不可恢复或 WebView 进程异常等明确条件归并非关键埋点报错最多提供疑似证据。六、分类器的关键是拒绝单信号定罪本地实验使用一个纯函数固定判定顺序先处理排除项再识别恢复随后才确认白屏只要证据不完整就降级为suspected。exportfunctionclassifyObservation(observation){if(observation.excluded)return{state:excluded}constcrossedobservation.visualBlankMsobservation.thresholdMsif(crossedobservation.keyElementSeen)return{state:recovered}if(crossed!observation.keyElementSeenobservation.terminalError){return{state:confirmed}}if(crossed||!observation.keyElementSeen||observation.terminalError){return{state:suspected}}return{state:healthy}}阈值比较使用严格大于因为历史文字口径是“超过 5 秒”。这类边界必须写进测试避免不同端产生不一致统计。七、7 项测试实际验证了什么实验运行在 Node.jsv22.19.0使用内置node:test没有安装第三方依赖。7 项测试覆盖长期空白加终止错误、只有长期空白、超时后恢复、已知排除页、快速可见、页面可见但脚本报错以及阈值相等的边界。tests 7 pass 7 fail 0 {confirmed:1,suspected:2,recovered:1,excluded:1,healthy:1}这些结果只证明示例规则与测试一致不证明真实像素算法有效也没有测量 WebView 截图开销、误报率或线上白屏下降幅度。八、指标要能推动发布决策有了可解释状态可以继续统计确认白屏率、超阈值恢复率、疑似事件确认率、关键元素就绪时间 P50/P75/P95并按 App、WebView、系统、网络、页面和资源包版本分组。发布系统可以先在灰度组比较新旧版本若确认白屏率显著上升或某个离线包版本集中触发confirmed暂停全量并回滚。阈值本身不能凭感觉设置应来自页面样本、用户等待预算和设备性能分层。九、上线前检查表与验证边界同时采集视觉、关键元素、导航/HTTP、资源、脚本和 Promise 信号任意单一错误不会直接升级为确认白屏五种分类结果和阈值边界都有测试事件包含算法版本、页面版本和资源包版本端侧不上传完整截图不记录用户敏感内容发布门禁使用确认白屏率和样本量不被单个偶发事件触发每次调整采样区、阈值或分类规则都重新标定。来源MDNWindowerroreventMDNWindowunhandledrejectioneventMDNPerformanceObserver本地零依赖白屏分类实验验证边界本文核验了 MDN 对错误事件、未处理 Promise 与 PerformanceObserver 的说明并完成零依赖分类实验历史截图参数来自脱敏资料只作为方法来源和测试样例。本文没有采集真实用户画面没有验证阈值、像素算法、WebView 开销、误报率或线上改善幅度新项目必须重新标定。