ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

TimeMe.js闲置检测算法揭秘:250ms轮询与事件驱动的平衡之道

2026/8/27 14:51:11 拓冰建站 浏览量
TimeMe.js闲置检测算法揭秘:250ms轮询与事件驱动的平衡之道 TimeMe.js闲置检测算法揭秘250ms轮询与事件驱动的平衡之道【免费下载链接】TimeMe.jsA JavaScript library to accurately time how long a user views a web page, disregarding idle time and time when the tab or window is minimized.项目地址: https://gitcode.com/gh_mirrors/ti/TimeMe.jsTimeMe.js 是一个 JavaScript 页面浏览时长统计库能准确记录用户真正在看网页的时间自动剔除闲置和切走标签页的时段。它的闲置检测既不是死板的定时轮询也不是纯靠事件监听而是用250ms 轮询 事件驱动的混合策略在精度与性能之间找到了巧妙的平衡点。下面带你拆解这套算法的设计思路。一、为什么简单计时不可靠如果你用Date.now()在页面加载和离开时各记一笔算出来的时长包含大量水分用户切到别的标签页去刷短视频了 ⏳用户泡杯咖啡回来鼠标半天没动 窗口被最小化挂着过夜TimeMe.js 要统计的是真实交互时长只有用户在页面、且正在操作或刚操作完的时间才算数。为此它必须回答两个问题用户什么时候人没了切标签页、失焦用户什么时候闲下来了长时间无鼠标键盘输入答案正是两种监听手段的分工协作。二、心跳线每 250ms 一跳的闲置计数器算法的核心是一个叫checkIdleStateRateMs的常量被固定设为250毫秒定义在 timeme.js 第 41 行库通过setInterval每 250ms 触发一次checkIdleState()第 344~348 行每跳一次闲置时长累加器currentIdleTimeMs就250ms一旦currentIdleTimeMs idleTimeoutMs默认 30 秒立刻判定用户闲置停止所有计时器也就是说闲置的进度条只靠轮询往前推。同时这个心跳还顺带完成了另一件事遍历检查callAfterTimeElapsedInSeconds()注册的回调——用户活跃满多少秒后弹窗提示之类的场景就是靠它逐跳探测触发的第 276~289 行。参数默认值含义checkIdleStateRateMs250ms闲置轮询的心跳间隔idleTimeoutMs30000ms30 秒多久无操作判定为闲置三、打断线4 个事件瞬间清零闲置计时轮询只能保证闲了多久算得准却不能保证人回来了算得快。好在用户一有动作事件会立刻打断闲置倒计时listForIdleEvents()timeme.js 第 338~342 行给页面挂了 4 个监听器事件覆盖的场景mousemove桌面端移动鼠标keyup键盘输入touchstart移动端触摸屏幕scroll滚动页面任意一个事件触发都会调用userActivityDetected()第 209~218 行做两件事把currentIdleCountdown清零、isUserCurrentlyIdle置为false——闲置倒计时瞬间归零而不是等到下一个 250ms 心跳若此前被判定为闲置还会触发callWhenUserReturns()回调让业务方知道用户回来了 一句话总结分工轮询负责推进闲置时间事件负责重置闲置时间。事件保证响应零延迟轮询保证即使浏览器对某些动作不派发事件闲置计时也绝不会漏算。四、标签页切换的捕捉页面可见性 窗口焦点双保险用户切走了是比闲置更严重的流失TimeMe.js 用两条事件线同时兜住第 306~336 行visibilitychange事件标签页在浏览器中显示/隐藏时触发。代码还做了向后兼容依次探测mozHidden、msHidden、webkitHidden等旧版厂商前缀老浏览器也能用window的blur/focus事件整个浏览器窗口失去/获得焦点时触发覆盖切到另一个 App的场景页面隐藏时调用triggerUserHasLeftPageOrGoneIdle()标记用户离开、触发callWhenUserLeaves()回调、并调用stopAllTimers()关闭全部计时段用户回来时则由triggerUserHasReturned()重新开启计时。时长本身以起止时间区间的方式存储在startStopTimes中第 82~125 行一段活跃期就是一条{startTime, stopTime}记录最终统计时把所有区间的差值累加——所以闲置和离屏的时段天然就不被计入。五、为什么偏偏是 250ms这是整个算法最见功力的取舍精度下限最坏情况下闲置判定会晚最多 250ms统计误差约 0.25 秒对页面浏览时长分析这种分钟级口径的业务完全无感性能上限每秒只跑 4 次极轻量的函数远低于requestAnimationFrame每秒约 60 次的开销移动端也不心疼电量可被事件纠偏心跳只是兜底节拍器任何真实交互都会被事件立即打断因此轮询再笨也不会造成体感延迟换成 1 秒轮询省一点 CPU但闲置判定误差变成秒级换成 50ms 轮询精度更高但白白消耗 5 倍资源。250ms 就是精度与成本的最佳公约数⚖️六、动手验证Demo 与单元测试打开 demo/index.html页面顶部有一个实时计时器闲置阈值被刻意设为 5 秒方便观察——停手 5 秒后计时立刻冻结动一下鼠标又恢复切走标签页同样生效tests/tests.js 中基于 QUnit 编写了完整的单元测试覆盖了callWhenUserLeaves/callWhenUserReturns回调、stopAllTimers等关键路径浏览器中打开 tests/testrunner.html 即可运行集成只需几行代码核心配置就是闲置阈值TimeMe.initialize({ currentPageName: my-home-page, idleTimeoutInSeconds: 30 // 闲置多少秒后停止计时 });详细 API 说明见 README.md压缩产物为 timeme.min.js通过npm install timeme.js --save也可安装。小结TimeMe.js 的闲置检测算法给了前端一个很好的范式参考用低频轮询250ms 心跳做状态推进与兜底用高频事件鼠标/键盘/触摸/滚动/可见性做即时纠偏两者各司其职最终用极小的运行时开销换来了真实交互时长的精准度量。如果你也在做页面停留时长、用户参与度分析这套粗粒度心跳 细粒度中断的混合思路值得直接抄作业 ✅【免费下载链接】TimeMe.jsA JavaScript library to accurately time how long a user views a web page, disregarding idle time and time when the tab or window is minimized.项目地址: https://gitcode.com/gh_mirrors/ti/TimeMe.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考