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

2020/09/25 15:01 · javascript ·  · 0评论

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

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

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

这是一个使用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>   

如果不使用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
    }
};

然后在需要的地方初始化函数(例如: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.onkeypress = resetTimer;
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根据您的需要。在这里,您可以看到它们之间的区别:Java中的窗口,屏幕和文档之间的区别是什么?

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

改善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使用率为零。

我一年前创建了一个小库:

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

描述:

小型的javascript库,用于报告用户在浏览器中的活动(离开,空闲,不查看网页,在其他标签中等)。与其他任何JavaScript库(例如jquery)无关。

Visual Studio用户可以通过以下方式从NuGet中获取它: PM> 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.
   }

})

类似于上面的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...
});

//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)))

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

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

我知道这是一个相对较旧的问题,但是我遇到了同样的问题,并且找到了一个很好的解决方案。

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

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

参见JsFiddle演示

(仅供参考:后端事件跟踪Leads browserload参见此内容

我的答案受到了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);
}());

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

这利用普通的JavaScript和立即调用的函数表达式以干净且自成体系的方式处理空闲超时。

先前的所有答案都有一个始终处于活动状态的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);
    }
}

http://jsfiddle.net/jndxq51o/

通过检测鼠标在表单主体上的移动并在最后一次移动时间更新全局变量,您可能会一起破解某些东西。然后,您需要运行一个间隔计时器,该计时器会定期检查上一次移动时间,并且如果自检测到上一次鼠标移动以来时间足够长,则应执行一些操作。

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

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

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

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

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

如果您以受支持的浏览器为目标(截至2018年12月为Chrome或Firefox),则可以尝试使用requestIdleCallback为不受支持的浏览器添加requestIdleCallback填充程序。

试试此代码,它可以完美地工作。

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";
    }
}
<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> 

我认为这个jquery代码是完美的,尽管是从上面的答案中复制和修改的!不要忘记在文件中包含jquery库!

所有这些解决方案的问题,尽管是正确的,但考虑到会话超时有价值的设置(使用PHP,.NET或Coldfusion开发人员的Application.cfc文件)时,都是不切实际的。上述解决方案设置的时间需要与服务器端会话超时同步。如果两者不同步,则可能会遇到麻烦,只会使用户感到沮丧和困惑。例如,服务器端会话超时可能设置为60分钟,但用户可能认为他/她是安全的,因为JavaScript空闲时间捕获增加了用户可以花在单个页面上的总时间。用户可能已经花了很长时间填写较长的表格,然后提交了。会话超时可能在处理表单提交之前开始。我倾向于给用户180分钟,然后使用JavaScript自动将用户注销。本质上,使用上面的一些代码来创建一个简单的计时器,但是没有捕获鼠标事件部分。这样,我的客户端和服务器端时间可以完美同步。如果您在用户界面中向用户显示时间,则不会造成混乱,因为这会减少时间。每次在CMS中访问新页面时,服务器端会话和JavaScript计时器都会重置。简单而优雅。如果用户在单个页面上停留超过180分钟,那么我认为该页面首先存在问题。随着它减少。每次在CMS中访问新页面时,服务器端会话和JavaScript计时器都会重置。简单而优雅。如果用户在单个页面上停留超过180分钟,那么我认为该页面首先存在问题。随着它减少。每次在CMS中访问新页面时,服务器端会话和JavaScript计时器都会重置。简单而优雅。如果用户在单个页面上停留超过180分钟,那么我认为该页面首先存在问题。

具有正确设置重置时间和绑定的纯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);
  });

}());

(部分受本主题前面的Equiman良好的核心逻辑启发。)

sessionExpiration.js


sessionExpiration.js轻巧但有效且可自定义。实施后,只需一行即可使用:

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

如果您不更改CSS,这就是实际操作的一个示例。

demo_image

我写了一个简单的jQuery插件,可以完成您想要的工作。

https://github.com/afklondon/jquery.inactivity

$(document).inactivity( {
    interval: 1000, // the timeout until the inactivity event fire [default: 3000]
    mouse: true, // listen for mouse inactivity [default: true]
    keyboard: false, // listen for keyboard inactivity [default: true]
    touch: false, // listen for touch inactivity [default: true]
    customEvents: "customEventName", // listen for custom events [default: ""]
    triggerAll: true, // if set to false only the first "activity" event will be fired [default: false]
});

该脚本将侦听鼠标,键盘,触摸和其他自定义事件的不活动(空闲),并触发全局“活动”和“不活动”事件。

希望这可以帮助 :)

只是一些想法,一两个探索的途径。

是否可以使函数每10秒运行一次,并检查“计数器”变量?如果可以的话,您可以将鼠标悬停在页面上,可以吗?如果是这样,请使用mouseover事件重置“计数器”变量。如果您的函数被调用,并且计数器超出了您预定的范围,请执行操作。

再说一遍,只是一些想法...希望能有所帮助。

我已经测试了此代码工作文件:

var timeout = null;
    var timee = '4000'; // default time for session time out.
    $(document).bind('click keyup mousemove', function(event) {

    if (timeout !== null) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function() {
              timeout = null;
            console.log('Document Idle since '+timee+' ms');
            alert("idle window");
        }, timee);
    });

这是我找到的最佳解决方案:http :
//css-tricks.com/snippets/jquery/fire-event-when-user-is-idle/

这是JS:

idleTimer = null;
idleState = false;
idleWait = 2000;

(function ($) {

    $(document).ready(function () {

        $('*').bind('mousemove keydown scroll', function () {

            clearTimeout(idleTimer);

            if (idleState == true) { 

                // Reactivated event
                $("body").append("<p>Welcome Back.</p>");            
            }

            idleState = false;

            idleTimer = setTimeout(function () { 

                // Idle Event
                $("body").append("<p>You've been idle for " + idleWait/1000 + " seconds.</p>");

                idleState = true; }, idleWait);
        });

        $("body").trigger("mousemove");

    });
}) (jQuery)

您可以使用以下提到的解决方案

var idleTime;
$(document).ready(function () {
         reloadPage();
        $('html').bind('mousemove click mouseup mousedown keydown keypress keyup submit change mouseenter scroll resize dblclick', function () {
            clearTimeout(idleTime);
            reloadPage();
        });
});
function reloadPage() {
    clearTimeout(idleTime);
    idleTime = setTimeout(function () {
        location.reload();
    }, 3000);
}

我使用这种方法,因为您不需要在事件触发时不断重置时间,而是只需记录时间即可生成空闲开始点。

           function idle(WAIT_FOR_MINS, cb_isIdle) {
            var self = this, 
                idle,
                ms = (WAIT_FOR_MINS || 1) * 60000,
                lastDigest = new Date(),
                watch;
            //document.onmousemove = digest;
            document.onkeypress = digest;
            document.onclick = digest;

            function digest() {
               lastDigest = new Date(); 
            }
            // 1000 milisec = 1 sec
            watch = setInterval(function(){
                if (new Date() - lastDigest > ms && cb_isIdel) {
                    clearInterval(watch);
                    cb_isIdle();
                }

            }, 1000*60);    
        },

根据@equiman提供的输入

class _Scheduler {
    timeoutIDs;

    constructor() {
        this.timeoutIDs = new Map();
    }

    addCallback = (callback, timeLapseMS, autoRemove) => {
        if (!this.timeoutIDs.has(timeLapseMS + callback)) {
            let timeoutID = setTimeout(callback, timeLapseMS);
            this.timeoutIDs.set(timeLapseMS + callback, timeoutID);
        }

        if (autoRemove !== false) {
            setTimeout(
                this.removeIdleTimeCallback, // Remove
                10000 + timeLapseMS, // 10 secs after
                callback, // the callback
                timeLapseMS, // is invoked.
            );
        }
    };

    removeCallback = (callback, timeLapseMS) => {
        let timeoutID = this.timeoutIDs.get(timeLapseMS + callback);
        if (timeoutID) {
            clearTimeout(timeoutID);
            this.timeoutIDs.delete(timeLapseMS + callback);
        }
    };
}

class _IdleTimeScheduler extends _Scheduler {
    events = [
        'load',
        'mousedown',
        'mousemove',
        'keydown',
        'keyup',
        'input',
        'scroll',
        'touchstart',
        'touchend',
        'touchcancel',
        'touchmove',
    ];
    callbacks;

    constructor() {
        super();
        this.events.forEach(name => {
            document.addEventListener(name, this.resetTimer, true);
        });

        this.callbacks = new Map();
    }

    addIdleTimeCallback = (callback, timeLapseMS) => {
        this.addCallback(callback, timeLapseMS, false);

        let callbacksArr = this.callbacks.get(timeLapseMS);
        if (!callbacksArr) {
            this.callbacks.set(timeLapseMS, [callback]);
        } else {
            if (!callbacksArr.includes(callback)) {
                callbacksArr.push(callback);
            }
        }
    };

    removeIdleTimeCallback = (callback, timeLapseMS) => {
        this.removeCallback(callback, timeLapseMS);

        let callbacksArr = this.callbacks.get(timeLapseMS);
        if (callbacksArr) {
            let index = callbacksArr.indexOf(callback);
            if (index !== -1) {
                callbacksArr.splice(index, 1);
            }
        }
    };

    resetTimer = () => {
        for (let [timeLapseMS, callbacksArr] of this.callbacks) {
            callbacksArr.forEach(callback => {
                // Clear the previous IDs
                let timeoutID = this.timeoutIDs.get(timeLapseMS + callback);
                clearTimeout(timeoutID);

                // Create new timeout IDs.
                timeoutID = setTimeout(callback, timeLapseMS);
                this.timeoutIDs.set(timeLapseMS + callback, timeoutID);
            });
        }
    };
}
export const Scheduler = new _Scheduler();
export const IdleTimeScheduler = new _IdleTimeScheduler();

您可能会使用列出的mousemove技巧检测到网页上的不活动状态,但这并不能告诉您该用户不在另一个窗口或选项卡的另一个页面上,或者该用户不在Word或Photoshop中,或者在WOW和只是目前不在查看您的页面。通常,我只是做预取并依靠客户端的多任务处理。如果您确实需要此功能,则可以在Windows中使用Activex控件来做一些事情,但这充其量是丑陋的。

这是在Angular中完成的AngularJS服务。

/* Tracks now long a user has been idle.  secondsIdle can be polled 
   at any time to know how long user has been idle. */
fuelServices.factory('idleChecker',['$interval', function($interval){
    var self = {
        secondsIdle: 0,
        init: function(){
            $(document).mousemove(function (e) {
                self.secondsIdle = 0;
            });
            $(document).keypress(function (e) {
                self.secondsIdle = 0;
            });
            $interval(function(){
                self.secondsIdle += 1;
            }, 1000)
        }
    }
    return self;
}]);

请记住,此空闲检查程序将在所有路径上运行,因此应在.run()有角度应用程序加载时对其进行初始化然后,您可以idleChecker.secondsIdle在每条路线内使用

myApp.run(['idleChecker',function(idleChecker){
    idleChecker.init();
}]);

反跳实际上是个好主意!此处为jQuery免费项目版本:

const derivedLogout = createDerivedLogout(30);
derivedLogout(); // it could happen that user too idle)
window.addEventListener('click', derivedLogout, false);
window.addEventListener('mousemove', derivedLogout, false);
window.addEventListener('keyup', derivedLogout, false); 

function createDerivedLogout (sessionTimeoutInMinutes) {
    return _.debounce( () => {
        window.location = this.logoutUrl;
    }, sessionTimeoutInMinutes * 60 * 1000 ) 
}

尽可能简单地检测鼠标何时移动:

var idle = false;

document.querySelector('body').addEventListener('mousemove', function(e) {
    if(idle!=false)idle = false;
});

var idleI = setInterval(function()
{   
    if(idle == 'inactive')
    {
        return;
    }

    if(idle == true)
    {
        idleFunction();
        idle = 'inactive';
        return;
    }

    idle = true;
}, 30000);// half the expected time, idle will trigger after 60s in this case.

function idleFuntion()
{
   console.log('user is idle');
}

好吧,您可以将click或mousemove事件附加到文档主体,以重置计时器。有一个您可以按时间间隔调用的函数,该函数可以检查计时器是否超过指定的时间(例如1000毫秒),然后开始预加载。

本文地址:http://javascript.askforanswer.com/ruheyouyadijiancejavascriptzhongdekongxianshijian.html
文章标签:
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!