SPA中Navigator.sendBeacon()请求堆叠问题排查与解决咨询
解决方案:移除组件卸载时的监听器
问题的核心是SPA页面导航时组件未清理事件监听器:每次进入视频页面组件,你都会添加一个页面可见性变化的监听器,但组件卸载(Inertia导航离开)时没有移除它,导致监听器不断累积。当页面隐藏(切换标签/关闭)时,所有累积的监听器都会触发,发送对应数量的Beacon请求。
修正后的代码示例
在Vue 3组件中,利用组件生命周期钩子管理监听器的添加与移除:
<script setup> import { ref, onMounted, onUnmounted } from 'vue' const props = defineProps(['currentLesson']) const video = ref(null) const sendBeacon = () => { // 修正模板字符串:用反引号解析变量 const url = `/api/video/${props.currentLesson.media.id}/progress` const timeLine = { progress: video.value.currentTime, duration: video.value.duration } // 标准判断页面是否隐藏 if (!document.hidden) return const data = new Blob([JSON.stringify(timeLine)], { type: 'application/json' }) navigator.sendBeacon(url, data) } onMounted(() => { // 监听页面可见性变化事件(修正事件名:visibilitychange) document.addEventListener('visibilitychange', sendBeacon) }) onUnmounted(() => { // 组件卸载时必须移除监听器,避免累积 document.removeEventListener('visibilitychange', sendBeacon) }) </script>
关键说明
- 清理监听器:在
onUnmounted钩子中移除监听器,是解决请求堆叠的核心操作。Inertia导航离开页面时,组件会执行卸载钩子,此时移除监听器就能避免后续触发多余请求。 - 修正模板字符串:原代码中用单引号包裹URL会导致变量无法解析,改为反引号才能正确生成对应视频的进度统计接口地址。
- 标准事件与判断:使用Page Visibility API的
visibilitychange事件和document.hidden状态判断,替代原代码中可能错误的statechange事件,确保逻辑符合规范。
额外注意事项
- 不要在全局作用域添加监听器,必须绑定到单个视频组件的生命周期内,避免跨页面的监听器干扰。
- 如果使用Inertia的
preserveState或partialReload特性,要确保组件卸载逻辑依然正常执行,避免监听器残留。
内容的提问来源于stack exchange,提问作者Daniel S
相关产品推荐
相关产品推荐

