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

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

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


当前回答

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

其他回答

<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库!

下面是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.
   }
   
})

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

如果是,使用鼠标悬停事件重置“counter”变量。如果函数被调用,并且计数器在您预先确定的范围之上,那么执行您的操作。

(部分灵感来自Equiman回答的良好核心逻辑。)

sessionExpiration.js


sessionExpiration.js是轻量级的,但有效和可定制的。一旦实现,只在一行中使用:

sessionExpiration(idleMinutes, warningMinutes, logoutUrl);

Affects all tabs of the browser, not just one. Written in pure JavaScript, with no dependencies. Fully client side. (If so wanted.) Has warning banner and countdown clock, that is cancelled by user interaction. Simply include the sessionExpiration.js, and call the function, with arguments [1] number of idle minutes (across all tabs) until user is logged out, [2] number of idle minutes until warning and countdown is displayed, and [3] logout url. Put the CSS in your stylesheet. Customize it if you like. (Or skip and delete banner if you don't want it.) If you do want the warning banner however, then you must put an empty div with ID sessExpirDiv on your page (a suggestion is putting it in the footer). Now the user will be logged out automatically if all tabs have been inactive for the given duration. Optional: You may provide a fourth argument (URL serverRefresh) to the function, so that a server side session timer is also refreshed when you interact with the page.


这是一个例子,如果你不改变CSS,它看起来是什么样子的。

Debounce其实是个好主意!下面是一个用于无jquery项目的版本:

const derivedLogout = createDerivedLogout(30);
derivedLogout(); // It could happen that the user is 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 )
}