page lifecycle api 不提供低电量监听,需组合 navigator.getbattery()、visibilitychange 和节流信号判断;因兼容性差,应以页面不可见+低电量+raf拉长为触发条件,用时间戳采样节流 raf,避免 freeze 中修改逻辑。

Page Lifecycle API 本身不提供低电量状态监听
Page Lifecycle API 的 freeze、resume、pagehide 等事件只响应浏览器对页面执行状态的干预(如冻结、缓存、卸载),和设备电量无关。想感知低电量,必须用 navigator.getBattery() —— 但它在 Safari 和多数移动浏览器中**完全不支持**,连 fallback 都难做。
真正可行的低电量降级路径是组合判断
不能只靠一个 API,得把电池状态、页面可见性、系统节流信号串起来。核心逻辑是:当页面不可见 + 电池低于阈值 + 浏览器已开始节流,才触发动画降频。
-
navigator.getBattery()成功时,监听battery.levelchange,level - 监听
document.addEventListener('visibilitychange'),仅在document.hidden === true且document.visibilityState === 'hidden'时考虑降频,避免分屏/画中画误判 - 检测浏览器是否已节流:用
performance.now()对比两次requestAnimationFrame的时间差,若间隔 > 100ms,说明 rAF 被拉长,可视为节流已生效 - 动画控制必须用
requestAnimationFrame驱动,禁用setInterval或 CSSanimation,否则降频逻辑无效
如何安全地动态调整 requestAnimationFrame 频率
不能直接“降低 rAF 频率”,因为 rAF 本身没有频率控制参数。实际做法是:用时间戳做采样节流,在每次 rAF 回调里判断是否达到渲染时机。
示例:
let lastRenderTime = 0;
const TARGET_FPS = 15; // 低电量时目标帧率
const FRAME_INTERVAL = 1000 / TARGET_FPS;
<p>function animate(timestamp) {
if (timestamp - lastRenderTime >= FRAME_INTERVAL) {
// 执行动画更新
updatePosition();
lastRenderTime = timestamp;
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);</p>
- 别在
freeze事件里改动画逻辑——此时 JS 即将被挂起,任何修改都无效 - 降频开关应放在
visibilitychange+getBattery回调里统一管理,而不是分散在各处 - 恢复高频时不要简单重置
lastRenderTime = 0,而要用performance.now()当前值,防止首帧跳变
容易被忽略的兼容性硬伤
最麻烦的不是代码怎么写,而是哪些地方根本走不通:
-
navigator.getBattery()在 Safari 全系、iOS WebView、大部分安卓定制浏览器中返回undefined,无法 polyfill - 某些 Android WebView 不派发
freeze,但会直接冻结页面,导致你依赖的节流判断失效 - Chrome 的节能模式(Battery Saver)会在后台 5 分钟后休眠标签页,此时
visibilitychange可能不触发,getBattery也拿不到数据 - 所有基于时间戳的节流都受系统时间调整影响,比如用户手动改了手机时间,
performance.now()不受影响,但Date.now()会跳变
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










