Page Lifecycle API 无法读取电池状态,需配合 Navigator.getBattery()(HTTPS下可用,Chrome已弃用、Safari不支持)或系统级API;visibilitychange/pagehide仅反映页面可见性,非电量变化。

Page Lifecycle API 本身不提供电池状态读取能力,它只负责监听页面可见性与运行状态变化;要监听电池状态,必须配合 Navigator.getBattery() 或操作系统级接口(如 Windows App SDK 的 PowerSettingRegisterNotification)——但后者无法在网页中直接调用。
为什么不能只靠 pagehide 或 visibilitychange 判断电池状态
这两个事件反映的是用户是否在看当前页面,不是设备是否在耗电。比如:用户开着网页但切到其他应用、标签页被 Chrome 自动休眠、甚至设备已进入 Frozen 状态——此时 visibilitychange 可能早已不触发,更不会告诉你电量只剩 12%。
常见错误现象包括:
- 误以为
document.hidden === true就该停掉所有定时器,结果后台同步任务被无差别中断,导致数据未保存 - 在
freeze事件里尝试调用navigator.getBattery(),但该 API 在部分浏览器(如 Safari)中已被移除或拒绝返回 Promise - 监听了
visibilitychange却没做防抖,频繁触发 UI 重绘,反而加剧 CPU 唤醒和电量消耗
如何安全获取并响应真实电池状态
Navigator.getBattery() 是目前唯一跨平台可用的 Web 电池 API,但它有明确限制:
- 仅在 HTTPS 环境下可用(
localhost除外) - Chrome 96+ 已将其标记为 deprecated,Firefox 仍支持,Safari 完全不支持
- 返回的
BatteryManager对象是只读的,无法主动触发充电/放电模拟
实操建议:
先检测支持性,再降级处理:
if ('getBattery' in navigator) {
navigator.getBattery().then(battery => {
if (battery.level < 0.2 && battery.dischargingTime < 600) {
enterLowPowerMode();
}
battery.addEventListener('levelchange', () => {
if (battery.level < 0.15) {
throttleAnimations();
}
});
});
} else {
// 降级方案:监听 visibilitychange + 页面冻结状态
document.addEventListener('visibilitychange', () => {
if (document.hidden && performance.now() > 300000) {
// 页面已隐藏超 5 分钟,按低功耗逻辑处理
enterLowPowerMode();
}
});
}
低功耗交互模式该关什么、不该关什么
盲目关闭所有 JS 功能会破坏用户体验,重点应放在「可暂停、非关键、高频唤醒」的行为上:
- ✅ 应暂停:
setInterval(() => fetch('/status'), 5000)、requestAnimationFrame动画、WebGL 渲染循环、未完成的fetch轮询 - ✅ 应降频:
IntersectionObserver的threshold调宽、减少resize监听器触发频率、延迟非首屏图片加载 - ❌ 不该停:
beforeunload事件、表单输入监听、本地存储写入(防止数据丢失)、WebSocket 心跳(若业务强依赖连接)
特别注意:Chrome 的节能模式(Balance / Max)会在后台标签页中主动限制 setTimeout 最小间隔(可能拉长至 1000ms),所以不要假设你的轮询一定能按预期频率执行。
Windows 平台开发者绕过浏览器限制的替代路径
如果你开发的是 WinUI 3 或打包为 MSIX 的桌面 Web 应用,可以跳过浏览器限制,直接使用 Windows App SDK 提供的电源管理能力:
- 监听
PowerSettingRegisterNotification注册系统级电源变更通知 - 通过
Microsoft.Windows.System.Power命名空间获取实时BatteryStatus和PowerSupplyStatus - 在应用进入
Passive或Hidden状态时,结合电池状态决定是否启用低功耗策略
这种组合方式才是真正可控的:页面生命周期告诉你“用户是否在用”,系统电源 API 告诉你“设备是否快没电了”。两者叠加,才能做出合理决策。
最容易被忽略的一点是:电池状态变化可能发生在任何时刻,包括页面已被冻结(Frozen)但尚未被丢弃(Discarded)的间隙——这时你既收不到事件,也无法执行 JS。唯一可靠的应对,是在进入 Hidden 前就做好状态快照,并设计可恢复的轻量级心跳机制。

















