日志上报怎么避免阻塞页面渲染?
我在做前端性能监控,想把错误日志和用户行为上报到服务器,但发现用 fetch 直接发请求会卡一下页面,尤其在低端机上很明显。有没有办法让上报完全不阻塞主线程?
试过用 navigator.sendBeacon,但有些老浏览器不支持,而且数据量大了好像也不稳定。现在纠结要不要用 Web Worker,但又担心兼容性和维护成本。
比如我现在是这样上报的:
function reportLog(data) {
fetch('/log', {
method: 'POST',
body: JSON.stringify(data),
keepalive: true
});
}
加了 keepalive: true 有点改善,但还是偶尔会卡。有没有更稳妥的方案?
1. 优先用 sendBeacon 但要有 fallback
2. 对大数据量做分片处理
3. 用 requestIdleCallback 调度
具体来说可以这样改进:
为什么这样设计:
1. sendBeacon 是专门为日志上报设计的API,浏览器会保证请求完成,即使页面关闭。但确实有兼容性问题,所以要做fallback。
2. 大数据分片是因为我发现超过30KB的包在低端机上处理时间明显变长,而且有些移动网络对单次请求大小有限制。
3. requestIdleCallback 可以让浏览器在空闲时才执行上报任务,比直接setTimeout更智能。但要注意设置timeout避免一直不执行。
4. keepalive确实有用,它允许请求在页面unload后继续,但浏览器实现有差异,我遇到过某些Android WebView下还是会有轻微卡顿。
实际项目中我们还加了失败重试和本地存储兜底,不过核心思路就是这个。用下来在低端机上也能保持流畅,兼容性覆盖到IE10+。