如何检测 JavaScript 中的空闲时间

IT技术 javascript
2021-01-17 04:20:52

是否可以在 JavaScript 中检测“空闲”时间?

我的主要用例可能是预取或预加载内容。

我将空闲时间定义为用户不活动或没有任何 CPU 使用率的时间段

6个回答

这是一个使用 jQuery 处理 mousemove 和 keypress 事件的简单脚本。如果时间到期,页面会重新加载。

<script type="text/javascript">
    var idleTime = 0;
    $(document).ready(function () {
        // Increment the idle time counter every minute.
        var idleInterval = setInterval(timerIncrement, 60000); // 1 minute

        // Zero the idle timer on mouse movement.
        $(this).mousemove(function (e) {
            idleTime = 0;
        });
        $(this).keypress(function (e) {
            idleTime = 0;
        });
    });

    function timerIncrement() {
        idleTime = idleTime + 1;
        if (idleTime > 19) { // 20 minutes
            window.location.reload();
        }
    }
</script>
@PietBinnenbocht 另外,如果你开始优化这样的事情,你也可以改变每个接受字符串的函数,比如'mousemove keydown click'使用位标志(Event.MOUSEMOVE | Event.KEYDOWN | Event.CLICK),因为它们比字符串操作快。但你真的想这样做吗?
2021-03-11 04:20:52
您在 $(document).ready(function() 正文之后缺少一个分号。此外,在调用 setInterval 时,它不会在函数名称周围使用引号,并且您不需要它后面的括号。只是:setInterval(timerIncrement, 60000)
2021-03-20 04:20:52
这对用户的系统来说不是很重吗?比方说,一个用户在一台不太重的电脑上使用相当旧的浏览器,在一个 javascript 应用程序中工作了半天,每次用户移动鼠标时它都会处理这些功能......我想知道这会不会'不影响用户体验...
2021-03-25 04:20:52
你可以简单地使用idleTime++;代替idleTime = idleTime + 1;
2021-03-27 04:20:52
@Jesse:你的建议都很好,代码应该是这样的。但我只是想指出,即使没有这些更改,代码也是功能齐全的。表达式语句末尾的分号是可选的,实际上您可以将字符串传递给setInterval,然后将其计算为 JavaScript。
2021-04-08 04:20:52

不使用 jQuery,只使用原生 JavaScript:

var inactivityTime = function () {
    var time;
    window.onload = resetTimer;
    // DOM Events
    document.onmousemove = resetTimer;
    document.onkeydown = resetTimer;

    function logout() {
        alert("You are now logged out.")
        //location.href = 'logout.html'
    }

    function resetTimer() {
        clearTimeout(time);
        time = setTimeout(logout, 3000)
        // 1000 milliseconds = 1 second
    }
};

并在需要的地方初始化函数(例如:onPageLoad)。

window.onload = function() {
  inactivityTime();
}

如果需要,您可以添加更多 DOM 事件。最常用的是:

document.onload = resetTimer;
document.onmousemove = resetTimer;
document.onmousedown = resetTimer; // touchscreen presses
document.ontouchstart = resetTimer;
document.onclick = resetTimer;     // touchpad clicks
document.onkeydown = resetTimer;   // onkeypress is deprectaed
document.addEventListener('scroll', resetTimer, true); // improved; see comments

或使用数组注册所需的事件

window.addEventListener('load', resetTimer, true);
var events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
events.forEach(function(name) {
 document.addEventListener(name, resetTimer, true);
});

DOM 事件列表:http : //www.w3schools.com/jsref/dom_obj_event.asp

请记住使用window,或document根据您的需要。在这里你可以看到它们之间的区别:JavaScript 中的 window、screen 和 document之间有什么区别?

代码更新@frank-conijn 和@daxchen 改进:window.onscroll如果滚动在可滚动元素内,则不会触发,因为滚动事件不会冒泡。在 中window.addEventListener('scroll', resetTimer, true),第三个参数告诉侦听器在捕获阶段而不是冒泡阶段捕获事件。

@mpsbhat 只需添加一个 console.log 或警报,看看是否有效。或注册此事件:document.onload = function () { inactivityTime(); }; document.onmousedown = function () { inactivityTime(); }; document.onkeypress = function () { inactivityTime(); }; document.ontouchstart = function () { inactivityTime(); };
2021-03-10 04:20:52
简单/优雅的解决方案我刚刚更新并添加了超时作为参数,例如: var inactivityTime = function (timeout) { 所以我们可以在外面控制它
2021-03-12 04:20:52
有一个标志 var notidle 会好得多;仅在事件上设置标志 = true。然后在resetTimer函数中测试notidle标志是否为true,如果是reset定时器,或者调用logout。这将消除不断重置计时器的复杂性开销。
2021-03-18 04:20:52
是的...工作。jsfiddle.net/mpsbhat/6b6mja5t/1谢谢@equiman
2021-03-25 04:20:52
绝对重置计时器是一种更直接/直观和准确的方法,而不是让超时做它的事情,当计时器本身可以成为(高精度)计数器时,只保留另一件事的整数计数。
2021-03-30 04:20:52

改进Equiman 的(原始)答案

function idleLogout() {
    var t;
    window.onload = resetTimer;
    window.onmousemove = resetTimer;
    window.onmousedown = resetTimer;  // catches touchscreen presses as well      
    window.ontouchstart = resetTimer; // catches touchscreen swipes as well 
    window.onclick = resetTimer;      // catches touchpad clicks as well
    window.onkeydown = resetTimer;   
    window.addEventListener('scroll', resetTimer, true); // improved; see comments

    function yourFunction() {
        // your function for too long inactivity goes here
        // e.g. window.location.href = 'logout.php';
    }

    function resetTimer() {
        clearTimeout(t);
        t = setTimeout(yourFunction, 10000);  // time is in milliseconds
    }
}
idleLogout();

除了有关活动检测的改进以及从document的更改之外window,该脚本实际上调用了该函数,而不是让它闲置。

它不会直接捕获零 CPU 使用率,但这是不可能的,因为执行函数会导致 CPU 使用率。用户不活动最终会导致 CPU 使用率为零,因此它确实间接地捕获了零 CPU 使用率。

顺便说一句onkeypress 被贬低使用 onkeydown
2021-03-14 04:20:52
只是想指出,window.onscroll如果滚动在可滚动元素内则不会触发,因为滚动事件不会冒泡。使用window.addEventListener('scroll', resetTimer, true),第三个参数告诉侦听器在capture阶段而不是bubble阶段(IE > 8)期间捕获事件请参阅此答案
2021-03-20 04:20:52
@DaxChen -- 没有document.onscroll同样的问题,如果滚动在可滚动子项内,则不会触发?
2021-03-29 04:20:52
是的,我说的重点是使用addEventListener而不是onscroll.
2021-03-31 04:20:52
我将用这些重要信息更新我的答案,以防止其他复制和粘贴我的错误。谢谢@DaxChen 和 Frank
2021-04-06 04:20:52

我创建了一个小型库来执行此操作:

https://github.com/shawnmclean/Idle.js

描述:

用于报告用户在浏览器中的活动的微型 JavaScript 库(离开、空闲、不看网页、在不同的选项卡中等)。它独立于任何其他 JavaScript 库,例如 jQuery。

Visual Studio 用户可以通过以下方式从 NuGet 获取它:

Install-Package Idle.js

这是tvanfosson 想法的一个粗略的 jQuery 实现

$(document).ready(function(){

   idleTime = 0;

   //Increment the idle time counter every second.
   var idleInterval = setInterval(timerIncrement, 1000);
   
   function timerIncrement()
   {
     idleTime++;
     if (idleTime > 2)
     {
       doPreload();
     }
   }
   
   //Zero the idle timer on mouse movement.
   $(this).mousemove(function(e){
      idleTime = 0;
   });
   
   function doPreload()
   {
     //Preload images, etc.
   }
   
})
这实际上不起作用,因为传递一个字符串来setInterval()评估全局范围内的表达式,因此它不会找到timerIncrement().ready 处理程序函数内的函数。这是永远不要将字符串传递给setInterval(). 只需传递一个实际的函数引用,你就不会遇到这个问题,因为它们是在当前作用域中计算的。
2021-03-30 04:20:52
谢谢,我不知道永远不需要将字符串传递给 setInterval。更新了我的答案。
2021-04-02 04:20:52
此解决方案不考虑键盘事件。
2021-04-04 04:20:52
永远不要传递setInterval字符串!只需将函数作为变量即可!
2021-04-09 04:20:52