
页面休眠时定时器会停,setTimeout 和 setInterval 不可靠
浏览器在标签页非活跃、屏幕熄灭或系统进入省电模式时,会主动降频甚至暂停 JavaScript 定时器——这不是 bug,是规范行为。Chrome、Edge、Firefox 在后台标签页中会把 setTimeout 最小间隔拉长到 1000ms 以上,Safari 更激进,可能直接冻结。
常见错误现象:setInterval(() => console.log('tick'), 500) 在切走标签页后,几秒才打印一次,甚至完全卡住;倒计时、心跳上报、实时进度条全部失准。
- 别指望靠增加定时器精度来“绕过”休眠,浏览器有硬性节流策略
- 若业务强依赖精确时间(如音视频同步、游戏帧逻辑),必须用
performance.now()做差值校准,而非依赖回调节奏 - 对非关键任务(如 UI 动画轮询),可监听
visibilitychange事件,在document.hidden === true时暂停逻辑,避免资源浪费
Screen Wake Lock API 是唯一标准唤醒锁方案,但兼容性有限
Screen Wake Lock API 允许页面请求系统保持屏幕常亮,它不阻止 CPU 休眠,但能防止屏幕自动关闭导致的定时器冻结(尤其在移动设备上)。注意:它不能唤醒已休眠的 CPU,也不能恢复被冻结的 JS 执行上下文。
使用前必须满足两个前提:document.visibilityState === 'visible' 且页面处于安全上下文(HTTPS 或 localhost)。
立即学习“前端免费学习笔记(深入)”;
- 调用前先检查支持性:
'wakeLock' in navigator,否则需降级为轮询可见性 + 提示用户手动保持亮屏 - 获取锁是异步操作:
navigator.wakeLock.request('screen')返回 Promise,失败时会抛出NotAllowedError(比如用户未交互就自动请求)或NotSupportedError - 必须显式释放:
wakeLock.release(),否则锁会一直持有——常见坑是页面跳转或组件卸载时忘记清理,导致其他页面无法唤醒
安卓 WebView 和 iOS WKWebView 对唤醒锁支持差异大
原生 App 内嵌 WebView 时,Screen Wake Lock API 行为受宿主控制。安卓 WebView(Chromium 内核)基本支持,但需 App 主动开启权限(如 android.permission.WAKE_LOCK);iOS WKWebView 则完全不支持该 API,连 'wakeLock' in navigator 都返回 false。
这意味着:同一套 H5 代码在 iOS 上无法通过标准 API 维持屏幕常亮,强行调用会静默失败。
- iOS 唯一可行路径是让 App 提供桥接接口(如
window.webkit.messageHandlers.keepScreenOn.postMessage({})),由原生层调用UIApplication.shared.isIdleTimerDisabled = true - 安卓若发现
navigator.wakeLock存在但request()拒绝,大概率是 App 未声明权限或未启用硬件唤醒能力 - 不要在 iOS 上尝试用
video.play()或audio.play()“黑科技”保活——iOS 15+ 已限制自动播放触发的屏幕常亮逻辑
没有万能解法,关键看场景是否真需要“持续执行”
很多所谓“要防休眠”的需求,其实只是怕用户切走后状态丢失或任务中断。这时候真正该做的不是锁屏,而是设计容错机制。
- 用
localStorage或IndexedDB实时存档关键状态,切回时用visibilitychange触发恢复逻辑 - 网络请求类任务(如上传、轮询)应带重试 + 时间戳校验,而不是依赖定时器连续触发
- 若必须维持长连接(如 WebRTC、WebSocket 心跳),优先靠服务端保活 + 客户端重连策略,而非前端死守屏幕
最常被忽略的一点:用户主动锁屏或切走,本身就是一种明确意图。强行唤醒或锁屏,既耗电又违背预期,反而容易被系统 kill 进程——尤其是 Android 后台限制越来越严。











