能力 · API
Idle Detection API
发布于 更新于
IdleDetector 告诉页面用户是否在你指定的阈值(至少一分钟)内与设备有过交互,以及屏幕是否已锁定;任一答案翻转时触发 change 事件。它是受 idle-detection 权限保护的 WICG 草案,用途是聊天应用的在线状态指示,以及在无人观看时暂停高开销工作。
支持仅限 Chromium:桌面与 Android 上的 Chrome 94,Edge 94 到 96 以及 Edge 114 起(中间版本移除了该接口),Opera 与 Samsung Internet 在对应的 Chromium 版本中支持。Firefox 与 Safari 的任何版本都没有实现(BCD api.IdleDetector)。
new IdleDetector()
IdleDetector.requestPermission()
idleDetector.start()idleDetector.start(options)构造函数不接受参数。requestPermission() 是静态方法,仅 [Exposed=Window],返回 Promise<PermissionState>,兑现为 "granted"、"denied" 或 "prompt"。start() 返回 Promise<undefined>,检测器进入 "started" 状态后兑现。整个接口带 [SecureContext],并且也暴露在专用 Worker 中:那里可以调用 start(),但不存在 requestPermission()。
start() 接受一个可选的 options 参数,类型为 IdleOptions 字典。
| 成员 | 类型 | 必填 | 说明 |
|---|---|---|---|
threshold |
unsigned long long([EnforceRange]) |
否 | 无交互多少毫秒后 userState 变为 "idle"。最小值 60,000,更小的值会拒绝 Promise。负数或非有限值因 [EnforceRange] 在绑定层抛出 TypeError。 |
signal |
AbortSignal |
否 | 中止该信号会停止检测器,并以信号的中止原因拒绝尚未完结的 start() Promise。 |
start() 兑现后,两个只读属性承载状态:userState 为 "active" 或 "idle",screenState 为 "locked" 或 "unlocked"。第一次 start() 完成前两者都是 null,所以要在 change 处理函数内或 await idleDetector.start() 之后读取,不要在 new IdleDetector() 之后同步读取。
规范定义了以下拒绝情形,顺序即算法的检查顺序。
| 方法 | 异常 | 条件 |
|---|---|---|
requestPermission() |
InvalidStateError |
文档不是 fully active。 |
requestPermission() |
NotAllowedError |
调用时没有瞬时用户激活;权限提示只能跟在点击或按键之后。 |
start() |
InvalidStateError |
文档不是 fully active,或检测器的内部状态不是 "stopped"(已在启动中或已启动)。 |
start() |
NotAllowedError |
文档不允许使用 idle-detection 这一受策略控制的特性(默认允许列表为 'self'),或启动检测器时 idle-detection 权限状态为 "denied"。 |
start() |
TypeError |
threshold 小于 60,000 ms。 |
start() |
信号的中止原因 | 调用 start() 时 options.signal 已中止,或 Promise 待定期间被中止。 |
Chromium 有一处偏离规范:Permissions Policy 拦截该特性时,start() 抛出 SecurityError,而不是以 NotAllowedError 拒绝(见实测框)。浏览器端监视器断开时,Chromium 还会以 NotSupportedError 和消息 Idle detection not available. 拒绝 start(),规范没有建模这一情形。
每个示例都先检测构造函数是否存在,在 IdleDetector 为 undefined 的 Firefox 与 Safari 中回退到页面自身的活动信号(visibilitychange、输入事件)。
一分钟无操作后显示「离开」在线状态徽标
Section titled “一分钟无操作后显示「离开」在线状态徽标”权限请求在 click 处理函数内运行;检测器在 Promise 兑现后启动,仍在同一个任务内,不会丢失激活。API 缺失时,回退逻辑在标签页隐藏时把用户标记为离开,这是那些浏览器能给出的唯一信号。
const badge = document.querySelector('#presence');const enable = document.querySelector('#enable-presence');
function markAway(isAway) { badge.textContent = isAway ? '离开' : '活跃';}
async function startPresence() { if (!('IdleDetector' in window)) { document.addEventListener('visibilitychange', () => { markAway(document.visibilityState === 'hidden'); }); return 'fallback'; }
const state = await IdleDetector.requestPermission(); if (state !== 'granted') return 'denied';
const detector = new IdleDetector(); detector.addEventListener('change', () => { markAway(detector.userState === 'idle' || detector.screenState === 'locked'); }); await detector.start({ threshold: 60_000 }); markAway(false); return 'started';}
enable.addEventListener('click', async () => { try { enable.hidden = (await startPresence()) !== 'denied'; } catch (err) { console.error(`${err.name}: ${err.message}`); }});返回 'denied' 时按钮保持可见,用户修改站点设置后可以重试;再次调用 requestPermission() 会直接兑现已存储的决定,不再弹出提示。
用户退出登录时用 AbortSignal 停止检测器
Section titled “用户退出登录时用 AbortSignal 停止检测器”没有 stop() 方法。结束监视的唯一方式是传给 start() 的 AbortSignal,它同时释放浏览器端的监视器。start() 兑现之后再中止不会拒绝任何东西;start() 待定期间中止则以中止原因拒绝该 Promise,所以下面的 catch 要区分主动中止与真正的失败。
const controller = new AbortController();
async function watchUntilSignOut(detector) { try { await detector.start({ threshold: 120_000, signal: controller.signal }); } catch (err) { if (err.name === 'AbortError') return; // start() 完结前已退出登录 throw err; }}
document.querySelector('#sign-out').addEventListener('click', () => { controller.abort();});controller.abort() 之后检测器回到 "stopped" 状态,同一实例可以带着新的信号再次启动;旧的 userState 与 screenState 值不再更新。
- Screen Wake Lock API,与之互补的「阻止屏幕锁定」请求
- Web Locks API,用户空闲后协调多个标签页之间的工作
- Firefox 上的 PWA
- Idle Detection API: start() method(wicg.github.io)
- Idle Detection API: requestPermission() method(wicg.github.io)
- IdleDetector browser compatibility(developer.mozilla.org)
规范
| 规范 | 状态 |
|---|---|
| Idle Detection API: IdleDetector interface | WICG 草案 |
| Idle Detection API: start() method | WICG 草案 |
| Idle Detection API: requestPermission() method | WICG 草案 |