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

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

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


当前回答

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

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

它不依赖于jQuery,不过您可能需要通过Babel来运行它以支持旧的浏览器。

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

其他回答

您可以在文档主体上附加一个单击或鼠标移动事件,以重置计时器。

有一个函数,你在定时间隔调用,检查定时器是否超过指定的时间(如1000毫秒),并开始你的预加载。

下面是一个在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;
}]);

请记住,这个空闲检查器将为所有路由运行,因此应该在angular应用程序加载时在.run()中初始化它。然后你可以使用idleChecker。在每个路由内的secondside。

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

您要求优雅,我创建了一个简单的类来支持惰性检查(具有空闲状态),除了命令方式(带有回调)之外。此外,当违反空闲时间时,该类支持“backToActive”。

class Idle {
    constructor(timeout = 10, idleCallback = null, backToActiveCallback = null, autoStart = true, backToActiveOnXHR = false) {
        this.timeout = timeout
        this.idleCallback = idleCallback
        this.backToActiveCallback = backToActiveCallback
        this.autoStart = autoStart // only F5
        this.backToActiveOnXHR = backToActiveOnXHR
        this.idle = false
        this.timer = null
        this.events = ['scroll', 'mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart']
        this.init()
    }

    init() {
        if(this.backToActiveOnXHR) {
            this.events.push('load')
        }
        this.events.forEach(name => {
            window.addEventListener(name, this.backToActive, true)
        })
        if(this.autoStart) {
            this.backToActive()
        }
    }

    goIdle = () => {
        this.idle = true
        if(!!this.idleCallback) {
            this.idleCallback(this.timeout)
        }
    }

    backToActive = () => {
        if(this.idle) {
            this.backToActiveCallback()
        }
        this.idle = false
        clearTimeout(this.timer)
        this.timer = setTimeout(this.goIdle, this.timeout * 1000)
    }
}

用法:

let idleCallback = timeout => { console.log(`Went idle after ${timeout} seconds`) }
let backToActiveCallback = () => { console.log('Back to active') }
let idle = new Idle(30, idleCallback, backToActiveCallback)

devtools的结果:

// Went idle after 30 seconds <--- goes idle when no activity is detected
// Back to active <--- when the user is detected again

支持懒惰的好处:

setInterval(() => {
    common.fetchApi('/api/v1/list', { status: idle.idle ? 'away' : 'online' }).then(/* show a list of elements */)
}, 1000 * 5)

你为什么要一张惰性支票?有时我们使用周期性的XHR(带setInterval),即当用户观看航班、乘车、电影、订单等列表时。对于每个XHR,我们可以添加关于他/她的活动状态(在线/离开)的信息,这样我们就可以了解系统中的活跃用户。

我的课程是基于Equiman和Frank Conijn的回答。

所有前面的答案都有一个始终活动的鼠标移动处理程序。如果处理程序是jQuery,那么jQuery执行的额外处理可以加起来。特别是当用户使用游戏鼠标时,每秒可能发生多达500个事件。

这个解决方案避免处理每一个鼠标移动事件。这导致一个小的时间误差,但你可以调整你的需要。

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

    function startTimer() {
        timeout = setTimeout(onExpires, millis);
        document.addEventListener("mousemove", onActivity);
        document.addEventListener("keydown", onActivity);
        document.addEventListener("touchstart", 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);
        document.removeEventListener("touchstart", onActivity);
        setTimeout(startTimer, 1000);
    }
}

http://jsfiddle.net/9exz43v2/

JavaScript没有办法告诉CPU的使用情况。这将打破运行在沙盒中的JavaScript。

除此之外,连接页面的onmouseover和onkeydown事件可能会工作。

你也可以在onload事件中使用setTimeout来调度延迟后调用的函数。

// Call aFunction after 1 second
window.setTimeout(aFunction, 1000);