能省,但需主动响应visibilitychange事件——浏览器只通知页面隐藏,不自动停定时器、动画等;必须手动关停高频、视觉密集、持续占用cpu/gpu或网络的逻辑,如轮询、requestanimationframe、视频播放、webgl渲染及非关键埋点。

能省,但得你主动响应 visibilitychange 事件——浏览器不会自动停掉定时器、动画或请求,它只负责告诉你“页面现在看不见了”。关键不是 API 本身多强大,而是你有没有在 hidden 状态下及时关停那些“用户看不到却还在拼命跑”的逻辑。
哪些操作必须暂停
重点盯住高频、视觉密集、持续占用 CPU/GPU 或网络的逻辑:
- setInterval / setTimeout 轮询:比如每 3 秒 fetch 新消息。隐藏时不清除,CPU 就一直跑,电量和后台流量照耗。
-
requestAnimationFrame 动画循环:Canvas 绘图、CSS 动画驱动、粒子特效、实时图表重绘等。直接调用
cancelAnimationFrame(id)即可停掉,GPU 占用会立刻下降。 -
视频/音频播放:调用
video.pause()或audio.pause()。别设currentTime = 0,否则丢失用户进度。 -
WebGL 渲染帧:停掉
render()调用,避免无意义 GPU 持续工作。 -
非关键日志与埋点上报:把行为数据暂存在数组里,等回到
visible状态再批量发送,减少小包请求和电量开销。
如何正确监听可见性变化
现代浏览器(Chrome/Firefox/Edge/Safari 13.1+)已统一支持标准事件名,可直接使用:
document.addEventListener('visibilitychange', () => {<br> if (document.visibilityState === 'hidden') { /* 停资源 */ }<br> else { /* 恢复资源,注意防重复启动 */ }<br>});
若需兼容 IE10 或老旧 Android WebView,需做前缀探测:
先检查 document.hidden 是否存在;不存在则跳过。再用 ['', 'webkit', 'ms', 'moz'].find(...) 找出当前前缀,注册带前缀的事件(如 webkitvisibilitychange)。
容易踩的坑
visibilitychange 是信号,不是指令——它不保证实时触发,快速切两次标签页,事件可能被合并或延迟几毫秒;它也不代表页面即将卸载(那是 pagehide 或 beforeunload 的职责)。
常见错误包括:
- 误以为
document.hidden = true能手动模拟隐藏(实际是只读属性,设了无效); - 恢复时盲目重启定时器,没检查是否已被手动清除,导致多个同功能定时器并存;
- 混淆
<div hidden> 和 <code>document.visibilityState——前者只是 CSS 显隐,后者是浏览器窗口级生命周期状态; - WebView 场景下未确认 visibility 支持,部分老版本始终返回
visible,导致逻辑失效。 - 轮播图、粒子动画、图表重绘 → 必停,内存常降 20%–40%;
- 心跳保活、弱网重试 → 可延长间隔(如从 5s 改为 30s),而非完全停;
- 用户输入监听、键盘快捷键 → 保留,保障返回后即时响应;
- 用
Set或数组集中管理活跃的interval和rafID,便于统一清理和恢复。
实用建议:分层管理资源
不要一刀切停所有定时器。可按业务重要性分级:











