如何优雅地检测JavaScript中的空闲时间?

Che*_*ian 451 javascript

是否可以在JavaScript中检测" 空闲 "时间?
我的主要用例可能是预取或预加载内容.

空闲时间:用户不活动或没有任何CPU使用的时间段

fre*_*doo 422

这是一个使用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>   
Run Code Online (Sandbox Code Playgroud)

  • 在$(document).ready(function()体之后你缺少一个分号.另外,在调用setInterval时,它不能使用函数名称周围的引号,你不需要括号后面的括号.只是:setInterval(timerIncrement,60000) (16认同)
  • @Jesse:你的建议都很好,这就是代码应该如何.但我只想指出即使没有这些更改,代码也完全正常运行.表达式语句末尾的分号是可选的,您实际上可以将字符串传递给`setInterval`,然后将其作为JavaScript进行求值. (9认同)
  • 这对用户的系统来说不重吗?比方说,一个用户在浏览器上使用相当旧的浏览器,在一个javascript应用程序中运行半天,并且每次用户移动他的鼠标时它都在处理这些功能......我想知道这是否赢了" t影响用户的体验...... (7认同)
  • 您可以简单地使用`idleTime ++;`而不是`idleTime = idleTime + 1;` (6认同)
  • @PietBinnenbocht另外,如果你开始优化这样的事情,你也可以改变每个带有像'mousemove keydown click'这样的字符串的函数来使用位标志(`Event.MOUSEMOVE | Event.KEYDOWN | Event.CLICK`),因为它们比字符串操作更快.但你真的**想要这样做吗? (5认同)
  • 我认为最好使用`keydown`事件(因为它会在keypress之前发生)+添加`click`事件.你可以用一种方法加入事件:`$(this).on('mousemove keydown click',function(){idleTime = 0;});` (2认同)
  • @Sander关于性能 - 将"0"分配给"idleTime"几乎没有成本.嘿,我甚至为你做了jsperf测试:http://jsperf.com/setting-values这是~660 MOps /秒,你真的想优化吗?不要过早优化,在遇到瓶颈时再进行优化.我可以向你保证,它不会是`idleTime = 0`. (2认同)
  • 当打开多个选项卡并且用户忘记与其中一个选项卡交互并处于后台时会发生什么? (2认同)

equ*_*man 320

不使用jQuery,只有JavaScript:

var inactivityTime = function () {
    var time;
    window.onload = resetTimer;
    // DOM Events
    document.onmousemove = resetTimer;
    document.onkeypress = 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
    }
};
Run Code Online (Sandbox Code Playgroud)

致谢: http ://forums.devshed.com/javascript-development-115/alert-time-inactivity-click-logout-501444.html

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

window.onload = function() {
  inactivityTime(); 
}
Run Code Online (Sandbox Code Playgroud)

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

document.onload = resetTimer;
document.onmousemove = resetTimer;
document.onmousedown = resetTimer; // touchscreen presses
document.ontouchstart = resetTimer;
document.onclick = resetTimer;     // touchpad clicks
document.onkeypress = resetTimer;
document.addEventListener('scroll', resetTimer, true); // improved; see comments
Run Code Online (Sandbox Code Playgroud)

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

记住使用window,或document根据您的需要.在这里你可以看到它们之间的区别:Javascript中的窗口,屏幕和文档有什么区别?

  • 我更喜欢简单的javascript方法. (50认同)
  • 当计时器本身可以是(高精度)计数器时,确定重置计时器是一种更直接/直观和准确的方法,而不是超时执行它,只保留另一个事物的整数计数. (4认同)
  • 有一个标志var notidle会更好;仅在事件上将该标志设置为true。然后在resetTimer函数中测试notidle标志是否为true,是否重置了定时器或调用注销。这将消除不断重置计时器的复杂性开销。 (4认同)
  • @mpsbhat只需添加一个console.log或一个警告,看看是否有效.或者注册这个事件:`document.onload = function(){inactivityTime(); }; document.onmousedown = function(){inactivityTime(); }; document.onkeypress = function(){inactivityTime(); }; document.ontouchstart = function(){inactivityTime(); };` (2认同)
  • 是的......工作.https://jsfiddle.net/mpsbhat/6b6mja5t/1​​/.谢谢@equiman (2认同)
  • 简单/优雅的解决方案我刚刚更新并添加了超时作为参数,例如:```var inactivityTime = function (timeout) {``` 所以我们可以在外面控制它 (2认同)
  • 我不想覆盖任何现有的事件处理程序,所以我使用了:`window.addEventListener(“ load”,resetTimer,true); [“ mousedown”,“ mousemove”,“ keypress”,“ scroll”,“ touchstart” ] .forEach(function(name){document.addEventListener(name,resetTimer,true);});`受@JackTheKnife的回答启发 (2认同)

Fra*_*ijn 72

改进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.onkeypress = 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();
Run Code Online (Sandbox Code Playgroud)

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

它没有直接捕获零CPU使用率,但这是不可能的,因为执行一个函数会导致CPU使用率.并且用户不活动最终导致CPU使用率为零,因此间接地实现零CPU使用率.

  • 只是想指出,如果在可滚动元素内滚动,则“ window.onscroll”将不会触发,因为滚动事件不会冒泡。使用`window.addEventListener('scroll',resetTimer,true)`,第三个参数告诉侦听器在`capture`阶段而不是`bubble`阶段(IE&gt; 8)捕获事件,[查看此答案](https: //stackoverflow.com/a/32954565/4997172) (3认同)
  • 是的,我要说的是使用addEventListener而不是onscroll。 (2认同)
  • 顺便说一句 [onkeypress 已弃用](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onkeypress) 使用 [onkeydown](https://developer.mozilla.org/en-US/文档/Web/API/GlobalEventHandlers/onkeydown) (2认同)

Sha*_*ean 33

我创建了一个小型库,它在一年前完成了这项工作:

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

描述:

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

Visual Studio用户可以通过以下方式从NuGet获取它: PM> Install-Package Idle.js


Pet*_*r J 31

这是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.
   }

})
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案不考虑键盘事件. (9认同)
  • 永远不要传递`setInterval`字符串!只需将函数作为变量! (7认同)

Tra*_*er1 24

类似于上面的Iconic解决方案(使用jQuery自定义事件)......

// use jquery-idle-detect.js script below
$(window).on('idle:start', function(){
  //start your prefetch etc here...
});

$(window).on('idle:stop', function(){
  //stop your prefetch etc here...
});
Run Code Online (Sandbox Code Playgroud)
//jquery-idle-detect.js
(function($,$w){
  // expose configuration option
  // idle is triggered when no events for 2 seconds
  $.idleTimeout = 2000;

  // currently in idle state
  var idle = false;

  // handle to idle timer for detection
  var idleTimer = null;

  //start idle timer and bind events on load (not dom-ready)
  $w.on('load', function(){
    startIdleTimer();
    $w.on('focus resize mousemove keyup', startIdleTimer)
      .on('blur',idleStart) //force idle when in a different tab/window
      ;
  ]);

  function startIdleTimer() {
    clearTimeout(idleTimer); //clear prior timer

    if (idle) $w.trigger('idle:stop'); //if idle, send stop event
    idle = false; //not idle

    var timeout = ~~$.idleTimeout; // option to integer
    if (timeout <= 100) timeout = 100; // min 100ms
    if (timeout > 300000) timeout = 300000; // max 5 minutes

    idleTimer = setTimeout(idleStart, timeout); //new timer
  }

  function idleStart() {
    if (!idle) $w.trigger('idle:start');
    idle = true;
  }

}(window.jQuery, window.jQuery(window)))
Run Code Online (Sandbox Code Playgroud)


Kru*_*tik 20

你可以用下划线jquery更优雅地做到这一点-

$('body').on("click mousemove keyup", _.debounce(function(){
    // do preload here
}, 1200000)) // 20 minutes debounce
Run Code Online (Sandbox Code Playgroud)


joh*_*ose 15

我的回答是受到vijay的回答的启发,但它是一个更短,更通用的解决方案,我认为我会分享给任何可能有帮助的人.

(function () { 
    var minutes = true; // change to false if you'd rather use seconds
    var interval = minutes ? 60000 : 1000; 
    var IDLE_TIMEOUT = 3; // 3 minutes in this example
    var idleCounter = 0;

    document.onmousemove = document.onkeypress = function () {
        idleCounter = 0;
    };

    window.setInterval(function () {
        if (++idleCounter >= IDLE_TIMEOUT) {
            window.location.reload(); // or whatever you want to do
        }
    }, interval);
}());
Run Code Online (Sandbox Code Playgroud)

按照目前的情况,此代码将立即执行,并在没有鼠标移动或按键3分钟后重新加载当前页面.

这利用普通的vanilla JavaScript和一个立即调用的函数表达式来以一种干净和自包含的方式处理空闲超时.


DDa*_*Dan 15

我知道这是一个相对古老的问题,但我遇到了同样的问题,我发现了一个非常好的解决方案.

我用过:jquery.idle ,我只需要这样做:

$(document).idle({
  onIdle: function(){
    alert('You did nothing for 5 seconds');
  },
  idle: 5000
})
Run Code Online (Sandbox Code Playgroud)

参见JsFiddle演示.

(仅供参考:请参阅此内容以了解后端事件跟踪引导浏览器负载)


Hai*_*han 14

以前的所有答案都有一个始终有效的mousemove处理程序.如果处理程序是jQuery,jQuery执行的附加处理可以加起来.特别是如果用户使用游戏鼠标,则每秒可发生多达500个事件.

此解决方案避免处理每个mousemove事件.这会导致小的定时误差,但您可以根据需要进行调整.

function setIdleTimeout(millis, onIdle, onUnidle) {
    var timeout = 0;
    startTimer();

    function startTimer() {
        timeout = setTimeout(onExpires, millis);
        document.addEventListener("mousemove", onActivity);
        document.addEventListener("keydown", onActivity);
    }

    function onExpires() {
        timeout = 0;
        onIdle();
    }

    function onActivity() {
        if (timeout) clearTimeout(timeout);
        else onUnidle();
        //since the mouse is moving, we turn off our event hooks for 1 second
        document.removeEventListener("mousemove", onActivity);
        document.removeEventListener("keydown", onActivity);
        setTimeout(startTimer, 1000);
    }
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/jndxq51o/

  • +1 这就是我所做的 - mousemove 处理程序会导致缓慢和缩短电池寿命,因此如果您能承受较小的计时错误,则仅定期打开它是一个好主意。我通常使用空闲时间检测来自动发出会话到期警告(例如“你还在吗?”),所以在用户“空闲”之前我往往有很多分钟,在这种情况下,一个小的计时错误完全无关紧要。 (2认同)
  • 使用“keydown”比使用“keypress”更好,因为“keypress”事件不会检测到箭头键。因此,如果用户使用箭头键导航页面,无论如何它都会变为空闲。 (2认同)

tva*_*son 13

您可以通过检测表单主体上的鼠标移动并使用最后一个移动时间更新全局变量来解决某些问题.然后,您需要运行间隔计时器,定期检查最后一次运动时间,如果检测到最后一次鼠标移动已经足够长,则会执行一些操作.

  • 我冒昧地在 jQuery 中实现了你的想法。 (2认同)

raj*_*ite 6

如果您定位支持的浏览器(自2018年12月起为Chrome或Firefox),您可以试用requestIdleCallback并为不支持的浏览器添加requestIdleCallback填充程序.


Fom*_*Fom 6

(部分受到Equiman 答案的良好核心逻辑的启发。)

sessionExpiration.js


sessionExpiration.js是轻量级但有效且可定制的。实施后,仅在一行中使用:

sessionExpiration(idleMinutes, warningMinutes, logoutUrl);
Run Code Online (Sandbox Code Playgroud)
  • 影响浏览器的所有选项卡,而不仅仅是一个。
  • 纯 JavaScript 编写,没有依赖项。完全客户端。
  • (如果需要。)具有警告横幅倒计时时钟,可通过用户交互取消。
  • 只需包含sessionExpiration.js并调用该函数,参数为[1]用户注销前的空闲分钟数(跨所有选项卡),[2]显示警告和倒计时前的空闲分钟数,以及[3]登出网址。
  • 将 CSS 放在样式表中。如果您愿意,可以自定义它。(或者,如果您不想要横幅,可以跳过并删除它。)
  • 但是,如果您确实想要警告横幅,那么您必须在您的页面上放置一个 ID 为sessExpirDiv的空 div (建议将其放在页脚中)
  • 现在,如果所有选项卡在给定的时间内都处于非活动状态,则用户将自动注销。
  • 可选:您可以为该函数提供第四个参数 (URL serverRefresh),以便在您与页面交互时也刷新服务器端会话计时器。

如果您不更改 CSS,这是一个实际效果示例。

演示图像


SPi*_*dey 5

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

    //Zero the idle timer on mouse movement.
    $('body').mousemove(function (e) {
     //alert("mouse moved" + idleTime);
     idleTime = 0;
    });

    $('body').keypress(function (e) {
      //alert("keypressed"  + idleTime);
        idleTime = 0;
    });



    $('body').click(function() {
      //alert("mouse moved" + idleTime);
       idleTime = 0;
    });

});

function timerIncrement() {
    idleTime = idleTime + 1;
    if (idleTime > 10) { // 10 minutes

        window.location.assign("http://www.google.com");
    }
}
</script> 
Run Code Online (Sandbox Code Playgroud)

我认为这个jquery代码是完美的,虽然从上面的答案复制和修改!donot忘了在你的文件中包含jquery库!


小智 5

试试这个完美的工作..

var IDLE_TIMEOUT = 10; //seconds
var _idleSecondsCounter = 0;

document.onclick = function () {
    _idleSecondsCounter = 0;
};

document.onmousemove = function () {
    _idleSecondsCounter = 0;
};

document.onkeypress = function () {
    _idleSecondsCounter = 0;
};

window.setInterval(CheckIdleTime, 1000);

function CheckIdleTime() {
    _idleSecondsCounter++;
    var oPanel = document.getElementById("SecondsUntilExpire");
    if (oPanel)
        oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
    if (_idleSecondsCounter >= IDLE_TIMEOUT) {
        alert("Time expired!");
        document.location.href = "SessionExpired.aspx";
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 应该有一个解释。例如,为什么它能完美地工作?想法/要点是什么?和之前的答案有什么不同? (2认同)

Jac*_*ife 5

纯 JavaScript,通过以下方式正确设置重置时间和绑定addEventListener

(function() {

  var t,
    timeout = 5000;

  function resetTimer() {
    console.log("reset: " + new Date().toLocaleString());
    if (t) {
      window.clearTimeout(t);
    }
    t = window.setTimeout(logout, timeout);
  }

  function logout() {
    console.log("done: " + new Date().toLocaleString());
  }
  resetTimer();

  //And bind the events to call `resetTimer()`
  ["click", "mousemove", "keypress"].forEach(function(name) {
    console.log(name);
    document.addEventListener(name, resetTimer);
  });

}());
Run Code Online (Sandbox Code Playgroud)


Cap*_*iel 5

我写了一个小的ES6类来检测活动,否则将在空闲超时时触发事件。它涵盖了键盘,鼠标和触摸,可以被激活和停用,并且具有非常精简的API:

const timer = new IdleTimer(() => alert('idle for 1 minute'), 1000 * 60 * 1);
timer.activate();
Run Code Online (Sandbox Code Playgroud)

依赖于jQuery的,虽然你可能需要通过通天运行它支持旧版浏览器。

https://gist.github.com/4547ef5718fd2d31e5cdcafef0208096

一旦收到一些反馈,我可能会将其作为npm软件包发布。


Mar*_*llo 2

是否可以让一个函数每 10 秒运行一次,并检查“计数器”变量?如果可能的话,您可以将鼠标悬停在页面上,不是吗?

如果是这样,请使用鼠标悬停事件重置“计数器”变量。如果您的函数被调用,并且计数器高于您预先确定的范围,则执行您的操作。


归档时间:

查看次数:

308474 次

最近记录:

6 年,2 月 前