Как элегантно определять простой в JavaScript?

Можно ли определить время < idle "в JavaScript?
Моим преимущественным случаем, вероятно, было бы предварительное извлечение или предварительная загрузка содержимого.

Время простоя: период бездействия пользователя или без использования ЦП

Ответ 1

Вот простой script с помощью 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>   

Ответ 2

Без использования 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 в соответствии с вашими потребностями. Здесь вы можете увидеть различия между ними: В чем разница между окном, экраном и документом в Javascript?

Код, обновленный с помощью @frank-conijn и @daxchen, улучшен: window.onscroll не сработает, если прокрутка внутри прокручиваемого элемента, потому что события прокрутки не всплывают. window.addEventListener('scroll', resetTimer, true), третий аргумент говорит слушателю перехватывать событие во время фазы захвата вместо фазы пузыря.

Ответ 3

Улучшение по 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();


Помимо улучшений, связанных с обнаружением активности и переходом от document к window, этот скрипт фактически вызывает функцию, а не позволяет ей бездействовать.

Он не улавливает нулевую загрузку ЦП напрямую, но это невозможно, потому что выполнение функции вызывает использование ЦП. А неактивность пользователя в конечном итоге приводит к нулевой загрузке ЦП, поэтому косвенно она отлавливает нулевую загрузку ЦП.

Ответ 4

Я создал небольшую библиотеку, которая делает это год назад:

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

Описание:

Крошечная библиотека javascript, чтобы сообщать о активности пользователя в браузере (прочь, простаивать, не смотреть на веб-страницу, на другой вкладке и т.д.). который не зависит от другие javascript-библиотеки, такие как jquery.

Пользователи Visual Studio могут получить его из NuGet: PM> Install-Package Idle.js

Ответ 5

Вот грубая реализация jQuery идеи tvanfosson:

$(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.
   }

})

Ответ 6

Аналогично решению 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)))

Ответ 7

Вы можете сделать это более элегантно с помощью underscore и jquery -

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

Ответ 8

Мой ответ был вдохновлен ответом 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 и выражение, вызываемое сразу же вызываемым}, чтобы обрабатывать тайм-ауты простоя в чистом и автономном режиме.

Ответ 9

Я знаю, это довольно старый вопрос, но у меня была та же проблема, и я нашел довольно хорошее решение.

Я использовал: jquery.idle и мне нужно было только сделать:

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

Смотрите демоверсию JsFiddle.

(Только для информации: см. Это для внутреннего отслеживания событий приводит к загрузке браузера)

Ответ 10

Все предыдущие ответы имеют всегда активный обработчик перемещения мыши. Если обработчиком является 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);
    }

    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/

Ответ 11

Возможно, вы могли бы взломать что-то вместе, обнаружив движение мыши по телу формы и обновив глобальную переменную с последним временем движения. Затем вам нужно запустить таймер с интервалом, который периодически проверяет последнее время движения и что-то делает, если он был достаточно длинным, поскольку было обнаружено последнее движение мыши.

Ответ 13

<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 является совершенным, хотя скопирован и изменен из ответов выше! donot забыли включить библиотеку jquery в ваш файл!

Ответ 14

Попробуйте этот код, он отлично работает.

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

Ответ 15

Я написал небольшой класс ES6 для обнаружения активности и запуска событий на время простоя. Он охватывает клавиатуру, мышь и сенсорный экран, может быть активирован и деактивирован и имеет очень тонкий API:

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

Он не зависит от jQuery, хотя вам может понадобиться запустить его через Babel для поддержки старых браузеров.

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

Я мог бы выпустить его как пакет npm, как только получу обратную связь.

Ответ 16

Чистый JavaScript с правильно установленным временем reset и привязками через 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);
  });

}());

Ответ 17

Я написал простой плагин 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]
});

script будет прослушивать неактивность (бездействия) мыши, клавиатуры, сенсорного экрана и других неактивных событий и пропустить глобальные события "активности" и "бездействия".

Надеюсь, что это поможет:)

Ответ 18

Я тестировал рабочий файл этого кода:

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

Ответ 19

Проблема со всеми этими решениями, хотя и правильная, они непрактичны, учитывая учетный набор тайм-аута сеанса, используя PHP,.NET или в файле Application.cfc для разработчиков Coldfusion. Время, установленное вышеуказанным решением, должно синхронизироваться с тайм-аутом сеанса на стороне сервера. Если эти два не синхронизируются, вы можете столкнуться с проблемами, которые просто расстроят и запутают ваших пользователей. Например, тайм-аут сеанса на стороне сервера может быть установлен на 60 минут, но пользователь может поверить, что он безопасен, потому что время ожидания простоя JavaScript увеличило общий период времени, который пользователь может потратить на одну страницу. Пользователь, возможно, провел длительное заполнение в длинной форме, а затем отправил его. Таймаут сеанса может начинаться до обработки формы. Я просто даю своим пользователям 180 минут, а затем использую JavaScript для автоматического входа пользователя в систему. По сути, используя некоторый код выше, чтобы создать простой таймер, но без захвата части события мыши. Таким образом, время моей клиентской и серверной сторон прекрасно синхронизируется. Нет никакой путаницы, если вы покажете пользователю время в пользовательском интерфейсе, так как оно уменьшится. Каждый раз, когда в CMS открывается новая страница, сеанс на стороне сервера и таймер JavaScript составляют reset. Простой и элегантный. Если пользователь остается на одной странице более 180 минут, я полагаю, что что-то не так со страницей, в первую очередь.

Ответ 20

Вот лучшее решение, которое я нашел: 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)

Ответ 21

Вы можете использовать нижеприведенное решение

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

Ответ 22

Я использую этот подход, так как вам не нужно постоянно reset время, когда происходит событие, вместо этого мы просто записываем время, это создает начальную точку простоя.

           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);    
        },

Ответ 23

(Частично вдохновлен хорошей базовой логикой Equiman ранее в этой теме.)

sessionExpiration.js


sessionExpiration.js является легким, но эффективным и настраиваемым. После внедрения используйте только одну строку:

sessionExpiration(idleMinutes, warningMinutes, logoutUrl);
  • Влияет на все вкладки браузера, а не только на одну.
  • Написан на чистом JavaScript, без каких-либо зависимостей. Полностью клиентская сторона.
  • (При желании.) Имеет предупреждающий баннер и часы с обратным отсчетом, которые отменяются при взаимодействии с пользователем.
  • Просто включите sessionExpiration.js и вызовите функцию с аргументами [1] количество минут простоя (на всех вкладках) до выхода пользователя из системы, [2] количество минут простоя до отображения предупреждения и обратного отсчета и [3] URL выхода из системы.
  • Поместите CSS в вашу таблицу стилей. Настройте его, если хотите. (Или пропустите и удалите баннер, если он вам не нужен.)
  • Однако если вы хотите, чтобы баннер с предупреждением, тогда вы должны поместить пустой div с идентификатором sessExpirDiv на своей странице (есть предложение поместить его в нижний колонтитул).
  • Теперь пользователь автоматически выйдет из системы, если все вкладки были неактивны в течение заданного времени.
  • Необязательно: Вы можете предоставить четвертый аргумент (URL serverRefresh) для функции, чтобы таймер сеанса на стороне сервера также обновлялся при взаимодействии со страницей.

Это пример того, как это выглядит в действии, если вы не измените CSS.

demo_image

Ответ 24

Всего несколько мыслей, аспект или два, чтобы исследовать.

Возможно ли, чтобы функция выполнялась каждые 10 секунд и проверяла ли она переменную "счетчик"? Если это возможно, у вас может быть указатель мыши на странице, не так ли? Если это так, используйте событие mouseover для reset переменной "счетчик". Если ваша функция вызывается, а счетчик находится выше диапазона, который вы предварительно определяете, выполните свое действие.

Опять же, только некоторые мысли... Надеюсь, что это поможет.

Ответ 25

Вероятно, вы можете обнаружить неактивность на своей веб-странице, используя перечисленные трюки mousemove, но это не скажет вам, что пользователь не находится на другой странице в другом окне или вкладке или что пользователь находится в Word или Photoshop, или WOW и просто не смотрит на вашу страницу в это время. Обычно я просто делаю предварительную выборку и полагаюсь на многозадачность клиента. Если вам действительно нужна эта функциональность, вы делаете что-то с элементом управления activex в окнах, но в лучшем случае это уродливо.

Ответ 26

Для других пользователей с одинаковой проблемой. Вот функция, которую я только что составил.

Он НЕ запускается при каждом движении мыши, которое пользователь делает, или очищает таймер каждый раз, когда движется мышь.

<script>
// Timeout in seconds
var timeout = 10; // 10 seconds

// You don't have to change anything below this line, except maybe
// the alert('Welcome back!') :-)
// ----------------------------------------------------------------
var pos = '', prevpos = '', timer = 0, interval = timeout / 5 * 1000;
timeout = timeout * 1000 - interval;
function mouseHasMoved(e){
    document.onmousemove = null;
    prevpos = pos;
    pos = e.pageX + '+' + e.pageY;
    if(timer > timeout){
        timer = 0;
        alert('Welcome back!');
    }
}
setInterval(function(){
    if(pos == prevpos){
        timer += interval;
    }else{
        timer = 0;
        prevpos = pos;
    }
    document.onmousemove = function(e){
        mouseHasMoved(e);
    }
}, interval);
</script>

Ответ 27

Вот услуга AngularJS для выполнения в Angular.

/* 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() при загрузке приложения angular. Затем вы можете использовать idleChecker.secondsIdle внутри каждого маршрута.

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

Ответ 28

Как можно проще определить, только когда мышь двигается:

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');
}

Ответ 29

Хорошо, вы можете прикрепить событие click или mousemove к телу документа, который сбрасывает таймер. Имейте функцию, которую вы вызываете с временными интервалами, которая проверяет, превышает ли таймер указанное время (например, 1000 миллисекунд) и начнет предварительную загрузку.

Ответ 30

Исправлено решение @freddoo, но оно не работало в течение 1 минуты, поэтому я немного изменил его, чтобы записать дату + время, когда пользователь последний раз нажал на страницу и в моей функции timerIncrement. Я вычисляю разницу между текущее время и время последнего щелчка, и если значение оказывается больше или равно значению таймаута, тогда я перенаправляю:

var clickedDate = new Date();
var idleTime = 1;//

function timerIncrement() {

    var nowDate = new Date();
    var diffMs = (nowDate - clickedDate); //Milliseconds between now & the last time a user clicked somewhere on the page
    var diffMins = Math.round(((diffMs % 86400000) % 3600000) / 60000); //Convert ms to minutes

    if (diffMins >= idleTime) {
        //Redirect user to home page etc...
    }
}

$(document).ready(function () {

    var idleInterval = setInterval(timerIncrement, 60000); // 1 minute

    $(this).click(function (e) {
        clickedDate = new Date();
    });

});