是否有可能在JavaScript中检测“空闲”时间?
我的主要用例可能是预取或预加载内容。
我将空闲时间定义为用户不活动或没有任何CPU使用的时间段
是否有可能在JavaScript中检测“空闲”时间?
我的主要用例可能是预取或预加载内容。
我将空闲时间定义为用户不活动或没有任何CPU使用的时间段
当前回答
你可以用Underscore.js和jQuery更优雅地做到这一点:
$('body').on("click mousemove keyup", _.debounce(function(){
// do preload here
}, 1200000)) // 20 minutes debounce
其他回答
我也遇到过同样的问题,但我找到了一个很好的解决方案。
我使用jquery。无所事事,我只需要做:
$(document).idle({
onIdle: function(){
alert('You did nothing for 5 seconds');
},
idle: 5000
})
参见JsFiddle演示。
(仅供参考:查看后端事件跟踪Leads browserload)
JavaScript没有办法告诉CPU的使用情况。这将打破运行在沙盒中的JavaScript。
除此之外,连接页面的onmouseover和onkeydown事件可能会工作。
你也可以在onload事件中使用setTimeout来调度延迟后调用的函数。
// Call aFunction after 1 second
window.setTimeout(aFunction, 1000);
我在这里提出的实现方法与其他答案在以下方面有所不同:
the idle event (by default named 'idleTimeSeconds') is fired every 10 seconds, so you can have multiple subscribers to the same event there is only one timer set per the document instance the timer is fired more often then the idle event (by default every 1 second vs every 10 seconds) - this will make for the default interval precision the timestamp of when the idle time started is recorded and is used to calculate the total idle time; other solutions propose to incrementally add seconds to the idle time counter, which is less prices because the actual delay of a timer may be longer than configured, see "Reasons for delays longer than specified in WindowOrWorkerGlobalScope.setTimeout()" for examples. the timer is never cancelled / reset, as proposed by some other solutions; cancelling and resetting timers is more expensive
文件Idle.js:
import $ from 'jquery';
export const IDLE_EVENT_NAME = 'idleTimeSeconds';
/**
* How often an 'idleTimeSeconds' event is fired on the document instance.
*
* @type {number}
*/
const IDLE_EVENT_RATE_SECONDS = 10;
/**
* How often the idle time is checked against the IDLE_EVENT_RATE_SECONDS.
*
* Should be much smaller than the value of IDLE_EVENT_RATE_SECONDS
* (the smaller the value is, the more precisely the event is fired) -
* because the actual delay may be longer, see "Reasons for delays
* longer than specified in WindowOrWorkerGlobalScope.setTimeout() for examples":
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Reasons_for_delays_longer_than_specified
*
* @type {number}
*/
const IDLE_TIMER_RATE_SECONDS = 1;
/**
* Because the actual timer delay may be longer, we track the timestamp
* when the idle time started, instead of incrementally adding to the total idle time.
* Having a starting point, we can always calculate the idle time precisely
* without accumulating delay errors.
*
* @type {number}
*/
let idleStartTimeMilliseconds;
/**
* Holds the interval reference.
*/
let idleInterval;
/**
* Holds the value of the latest idle time value
* for which the event was fired (integer value in seconds).
*
* The value is therefore factor of IDLE_EVENT_RATE_SECONDS.
*
* @type {number}
*/
let lastFiredSeconds;
const $document = $(document);
/**
* Resets the idle timer.
* Called on user interaction events, like keydown or touchstart.
*/
function resetIdleStartTime() {
// Reset the timestamp when the idle time started
idleStartTimeMilliseconds = (new Date).getTime();
// Reset the latest idle time value for which the even was fired
// (integer value in seconds).
lastFiredSeconds = 0;
}
/**
* Ticks every IDLE_TIMER_RATE_SECONDS, which is more often than the expected
* idle event firing rate.
*
* Fires the 'idleTimeSeconds' event on the document instance.
*/
function timerCallback() {
const nowMilliseconds = (new Date).getTime();
const idleTimeSeconds = Math.floor((nowMilliseconds - idleStartTimeMilliseconds) / 1000);
// When do we expect the idle event to be fired again?
// For example, if the event firing rate is 10 seconds,
// and last time it was fired at 40 seconds of idle time,
// the next one will be at 40 + 10 = 50 seconds.
const nextIdleSecondsToFire = lastFiredSeconds + IDLE_EVENT_RATE_SECONDS;
if (idleTimeSeconds >= nextIdleSecondsToFire) {
// Record last fired idle time that is factor of the rate,
// so that we keep firing the event as close to the desired rate as possible
lastFiredSeconds = nextIdleSecondsToFire;
$document.triggerHandler(IDLE_EVENT_NAME, [idleTimeSeconds]);
}
}
// Initialize the idle timer once only per the document instance
$(function() {
// Start the idle timer
idleInterval = setInterval(timerCallback, IDLE_TIMER_RATE_SECONDS * 1000);
// Reset the idle time start timestamp
$document.on('mousemove keydown mousedown touchstart', resetIdleStartTime);
});
示例用法(例如文件index.js):
import {IDLE_EVENT_NAME} from './Idle';
import $ from 'jquery';
$(function() {
$(document).on(IDLE_EVENT_NAME, function(e, idleSeconds) {
console.log('IDLE SECONDS:', idleSeconds);
});
});
示例输出(节选):
IDLE SECONDS: 580
IDLE SECONDS: 590
IDLE SECONDS: 600
IDLE SECONDS: 610
IDLE SECONDS: 620
IDLE SECONDS: 630
IDLE SECONDS: 640
IDLE SECONDS: 650
IDLE SECONDS: 660
IDLE SECONDS: 670
IDLE SECONDS: 680
IDLE SECONDS: 691
IDLE SECONDS: 700
IDLE SECONDS: 710
IDLE SECONDS: 720
IDLE SECONDS: 730
IDLE SECONDS: 740
IDLE SECONDS: 750
IDLE SECONDS: 761
IDLE SECONDS: 770
IDLE SECONDS: 780
IDLE SECONDS: 790
IDLE SECONDS: 800
IDLE SECONDS: 810
IDLE SECONDS: 820
IDLE SECONDS: 830
IDLE SECONDS: 840
IDLE SECONDS: 850
IDLE SECONDS: 860
IDLE SECONDS: 871
IDLE SECONDS: 880
IDLE SECONDS: 890
IDLE SECONDS: 900
IDLE SECONDS: 910
IDLE SECONDS: 921
上面的输出是当我切换到另一个选项卡并在那里做一些活动时产生的。可以看到,计时器有时会延迟(我想是因为在后台选项卡中,计时器以精确的速率被触发不是优先级)。但是空闲计时器仍然以正确的+/- 1秒的间隔触发。在这种情况下,1秒是空闲计时器的精度(通过idle .js中的IDLE_TIMER_RATE_SECONDS常量配置)。
下面是一个使用jQuery处理鼠标移动和按键事件的简单脚本。 如果时间过期,页面将重新加载。
<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>
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 )
}