面试防线:sendBeacon 失败时的降级与兜底策略
面试官提问:
“你为了防页面卸载丢失用了 navigator.sendBeacon,但 Beacon 其实有很多限制,比如传输的数据量有几十KB的上限限制,并且某些安全环境(如老旧浏览器或部分广告拦截器)会直接禁用它。如果 Beacon 发送失败或者不可用,你的 SDK 怎么兜底?”
核心回答思路 (STAR法则)
-
业务痛点 (Situation)
在实际生产环境中,有些复杂的页面跳转可能会同时带上大量的表单埋点和路径日志,一旦 Payload 超过了浏览器对sendBeacon的大小限制(一般在 64KB 左右),调用会直接返回 false 并抛弃数据。如果完全依赖它,必定会导致大体量核心数据漏报。 -
技术考量 (Task)
SDK 不能有单一故障点。必须具备环境探针(Feature Detection)能力,并在主策略碰壁时提供顺滑的无感降级手段,同时还要考虑页面正在卸载这个极端生死时刻的存活概率。 -
架构决策 (Action)
我在底层封装了一个名为HighReliabilityTransport的策略适配器,按照优先级执行降级:
- 优雅降级至 Fetch keepalive:如果是遇到了环境不支持(比如无
sendBeaconAPI)或者数据太大 Beacon 拒收,我立刻会降级使用现代的fetch(url, { body, keepalive: true })。keepalive标志位同样允许浏览器在后台接管发送,是比 Beacon 更灵活且容量更大的防卸载上报方案。 - 同步 XHR 的最后倔强:如果是老掉牙的 IE11 或旧版内核,连
keepalive都不支持,系统会作为最后手段降级到极其不受待见但绝对管用的同步请求var xhr = new XMLHttpRequest(); xhr.open(POST, url, false);。虽然它会稍微阻塞页面零点几秒的卸载体验,但我们在核心交易数据上权衡,宁可卡顿 100ms 也绝不能丢单。 - 本地存储 (IndexedDB) 落盘兜底:如果遇到断网或后端彻底宕机,所有网络层面的请求全军覆没,SDK 会在
catch捕获到异常的几毫秒内,立即将序列化的数据砸进IndexedDB或localStorage的离线队列中。等下次用户重新打开网站时,SDK 初始化后会先探活网络,将旧账连同缓存一并上报。
- 业务价值 (Result)
通过这套严密的梯形降级与兜底网络架构,我们不仅解决了常规的“防卸载丢失”,还在各种极端边界条件和古董浏览器下保证了 99.9% 级别的数据完备性,彰显了我们在前端底层通信网络层面的极客级掌控力。