页面关闭时如何可靠保存视频播放进度至数据库?
解决页面关闭前无法完成异步保存视频进度的问题
问题根源
beforeunload 事件的回调是同步执行逻辑,即便用了 async/await,浏览器也不会等待异步操作完成就会终止页面进程,导致你的 fetch 请求大概率被中断。
正确实现方式
方法1:使用 navigator.sendBeacon()
这是浏览器专为「页面卸载前发送数据」场景设计的API,它会异步发起请求,但浏览器会保证请求完成后再关闭页面,无需等待响应结果,适合仅需提交数据的场景。
修改代码如下:
const handleBeforeUnload = () => { save_timestamp(); }; const save_timestamp = () => { const v: IResumeVideo = { seconds: timeline.current, video_id: video_id }; // 将数据转为Blob格式适配sendBeacon要求 const blob = new Blob([JSON.stringify(v)], { type: 'application/json' }); navigator.sendBeacon('/api/save_video', blob); }; // 在React组件的useEffect中绑定/解绑事件 useEffect(() => { window.addEventListener('beforeunload', handleBeforeUnload); return () => { window.removeEventListener('beforeunload', handleBeforeUnload); }; }, [timeline.current, video_id]); // 根据实际依赖项调整
方法2:使用 fetch 的 keepalive 选项
如果需要对请求响应做处理(尽管页面关闭后处理响应意义有限),可以给 fetch 添加 keepalive: true 参数,强制浏览器维持请求直到完成:
const save_timestamp = async () => { const v: IResumeVideo = { seconds: timeline.current, video_id: video_id }; await fetch('/api/save_video', { method: 'POST', body: JSON.stringify(v), headers: { 'Content-Type': 'application/json' }, keepalive: true // 核心参数,确保请求不被中断 }); };
注意事项
navigator.sendBeacon()不支持自定义请求头(仅少数默认头可用),若后端要求特定请求头,优先用fetch + keepalive方案。- 提交的数据量尽量精简,避免因数据过大导致请求超时。
- 不同浏览器在页面刷新、标签关闭时的行为略有差异,建议在实际场景中多做测试。
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

