Hur man upptäcker inaktiv tid i JavaScript


Är det möjligt att upptäcka "inaktiv" tid i JavaScript?

Mitt primära användningsområde skulle förmodligen vara att förhämta eller förladda innehåll.

Jag definierar inaktiv tid som en period av användarinaktivitet eller utan någon CPU-användning

Svar #1

Med vanlig JavaScript:

var inactivityTime = function () {
    var time;
    window.onload = resetTimer;
    // DOM Events
    document.onmousemove = resetTimer;
    document.onkeydown = 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
    }
};

Och initialisera funktionen där du behöver den (till exempel: onPageLoad).

window.onload = function() {
  inactivityTime();
}

Du kan lägga till fler DOM-händelser om du behöver. De mest använda är:

document.onload = resetTimer;
document.onmousemove = resetTimer;
document.onmousedown = resetTimer; // touchscreen presses
document.ontouchstart = resetTimer;
document.onclick = resetTimer;     // touchpad clicks
document.onkeydown = resetTimer;   // onkeypress is deprectaed
document.addEventListener('scroll', resetTimer, true); // improved; see comments

Eller registrera önskade händelser med en array

window.addEventListener('load', resetTimer, true);
var events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
events.forEach(function(name) {
 document.addEventListener(name, resetTimer, true);
});

DOM-händelser lista: http://www.w3schools.com/jsref/dom_obj_event.asp

Kom ihåg att använda window eller document enligt dina behov. Här kan du se skillnaderna mellan dem: Vad är skillnaden mellan window, screen och document i JavaScript?

Kod Uppdaterad med @frank-conijn och @daxchen förbättrar: window.onscroll kommer inte att utlösas om rullning sker inuti ett rullbart element, eftersom scroll-händelser inte bubblar. I window.addEventListener('scroll', resetTimer, true), anger det tredje argumentet att lyssnaren ska fånga händelsen under fångstfasen istället för bubbel-fasen.

Svar #2

Här är ett enkelt skript som använder jQuery och hanterar mousemove- och keypress-händelser. Om tiden går ut, laddas sidan om.

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

Svar #3

Förbättrar på Equimans (ursprungliga) svar:

function noIdlingHere() {

    function yourFunction() {
        // your function for too long inactivity goes here
        // e.g. window.location.href = 'logout.php';
    }

    let t; // must be declared here
    function resetTimer() {
        clearTimeout(t); // global function
        t = setTimeout(yourFunction, 600000);  // time is in milliseconds (10 min)
    } 

    window.addEventListener('load', resetTimer, true);
    window.addEventListener('mousemove', resetTimer, true);
    window.addEventListener('mousedown', resetTimer, true);
    window.addEventListener('touchstart', resetTimer, true);
    window.addEventListener('touchmove', resetTimer, true);
    window.addEventListener('click', resetTimer, true);
    window.addEventListener('keydown', resetTimer, true);
    window.addEventListener('scroll', resetTimer, true);
    window.addEventListener('wheel', resetTimer, true);
}

noIdlingHere();

Förutom förbättringarna gällande aktivitetsdetektion och bytet från document till window, anropar detta skript faktiskt funktionen istället för att låta den ligga inaktiv.

Det fångar inte direkt noll CPU-användning, men det är omöjligt, eftersom att köra en funktion orsakar CPU-användning. Och användarens inaktivitet leder så småningom till noll CPU-användning, så indirekt fångar det noll CPU-användning.

Svar #4

Jag har skapat ett litet bibliotek som gör detta:

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

Beskrivning:

Litet JavaScript-bibliotek för att rapportera användaraktivitet i webbläsaren (borta, inaktiv, inte tittar på webbsidan, i en annan flik osv.) som är oberoende av andra JavaScript-bibliotek såsom jQuery.

Visual Studio-användare kan få det från NuGet genom att:

Install-Package Idle.js

Svar #5

Här är en grov jQuery-implementation av tvanfossons idé:

$(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 any action.
   $(this).bind('mousemove keydown scroll click', function (e) {
       idleTime = 0;
       //Do something
   });
   
   function doPreload()
   {
     //Preload images, etc.
   }
   
})

Svar #6

Liknande Peter Js lösning (med ett jQuery-anpassat evenemang)...

// Use the 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...
});

Fil 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 the 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; // Minimum 100 ms
    if (timeout > 300000)
      timeout = 300000; // Maximum 5 minutes

    idleTimer = setTimeout(idleStart, timeout); // New timer
  }

  function idleStart() {
    if (!idle)
      $w.trigger('idle:start');
    idle = true;
  }

}(window.jQuery, window.jQuery(window)))

Svar #7

Du kan göra det mer elegant med Underscore.js och jQuery:

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

Svar #8

Alla tidigare svar har en alltid-aktiv mousemove-hanterare. Om hanteraren är jQuery kan den extra bearbetning som jQuery utför adderas. Speciellt om användaren använder en gamingmus, eftersom så många som 500 händelser per sekund kan inträffa.

Denna lösning undviker att hantera varje musrörelsehändelse. Detta resulterar i ett litet tidsfel, men som du kan justera efter ditt behov.

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/

Svar #9

Mitt svar var inspirerat av Vijays svar, men är en kortare, mer allmän lösning som jag tänkte dela för alla som det kan hjälpa.

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

Som det ser ut nu kommer denna kod att köras omedelbart och ladda om din nuvarande sida efter 3 minuter utan musrörelser eller knapptryckningar.

Detta använder vanlig JavaScript och ett omedelbart anropat funktionsuttryck för att hantera inaktivitetsavbrott på ett rent och självinnehållande sätt.

Svar #10

Jag hade samma problem och jag hittade en ganska bra lösning.

Jag använde jquery.idle och jag behövde bara göra:

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

Se JsFiddle-demonstration.

(Bara för information: se detta för back-end-händelsespårning Leads browserload)

Svar #11

Om du riktar dig mot en stödd webbläsare (Chrome eller Firefox från och med december 2018) kan du experimentera med requestIdleCallback och inkludera requestIdleCallback-shim för webbläsare som inte stöds.

Svar #12

Du skulle förmodligen kunna fixa ihop något genom att upptäcka musrörelse på formulärets kropp och uppdatera en global variabel med den senaste rörelsetiden. Du skulle sedan behöva ha en intervalltimer som körs och periodiskt kontrollerar den senaste rörelsetiden och gör något om det har gått tillräckligt lång tid sedan senaste musrörelsen upptäcktes.

Svar #13

Jag skrev en liten ES6-klass för att upptäcka aktivitet och annars utlösa händelser vid inaktivitetstid. Den omfattar tangentbord, mus och beröring, kan aktiveras och avaktiveras och har ett mycket enkelt API:

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

Det beror inte på jQuery, även om du kanske behöver köra det genom Babel för att stödja äldre webbläsare.

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

Relaterade artiklar