How to detect idle time in JavaScript elegantly?

前端 未结 30 2369
别跟我提以往
别跟我提以往 2020-11-21 11:51

Is it possible to detect \"idle\" time in JavaScript?
My primary use case probably would be to pre-fetch or preload content.

Idle time:

相关标签:
30条回答
  • 2020-11-21 12:37

    Here is an AngularJS service for accomplishing in 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;
    }]);
    

    Keep in mind this idle checker will run for all routes, so it should be initialized in .run() on load of the angular app. Then you can use idleChecker.secondsIdle inside each route.

    myApp.run(['idleChecker',function(idleChecker){
        idleChecker.init();
    }]);
    
    0 讨论(0)
  • 2020-11-21 12:39

    I know it a relatively old question, but I had the same issue and I found a quite good solution.

    I used: jquery.idle and I only needed to do:

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

    See JsFiddle demo.

    (Just for Info: see this for back-end event tracking Leads browserload)

    0 讨论(0)
  • 2020-11-21 12:39

    If you are targeting a supported browser (Chrome or Firefox as of December 2018) you can experiment with the requestIdleCallback and include the requestIdleCallback shim for unsupported browsers.

    0 讨论(0)
  • 2020-11-21 12:39

    Based on the inputs provided by @equiman

    class _Scheduler {
        timeoutIDs;
    
        constructor() {
            this.timeoutIDs = new Map();
        }
    
        addCallback = (callback, timeLapseMS, autoRemove) => {
            if (!this.timeoutIDs.has(timeLapseMS + callback)) {
                let timeoutID = setTimeout(callback, timeLapseMS);
                this.timeoutIDs.set(timeLapseMS + callback, timeoutID);
            }
    
            if (autoRemove !== false) {
                setTimeout(
                    this.removeIdleTimeCallback, // Remove
                    10000 + timeLapseMS, // 10 secs after
                    callback, // the callback
                    timeLapseMS, // is invoked.
                );
            }
        };
    
        removeCallback = (callback, timeLapseMS) => {
            let timeoutID = this.timeoutIDs.get(timeLapseMS + callback);
            if (timeoutID) {
                clearTimeout(timeoutID);
                this.timeoutIDs.delete(timeLapseMS + callback);
            }
        };
    }
    
    class _IdleTimeScheduler extends _Scheduler {
        events = [
            'load',
            'mousedown',
            'mousemove',
            'keydown',
            'keyup',
            'input',
            'scroll',
            'touchstart',
            'touchend',
            'touchcancel',
            'touchmove',
        ];
        callbacks;
    
        constructor() {
            super();
            this.events.forEach(name => {
                document.addEventListener(name, this.resetTimer, true);
            });
    
            this.callbacks = new Map();
        }
    
        addIdleTimeCallback = (callback, timeLapseMS) => {
            this.addCallback(callback, timeLapseMS, false);
    
            let callbacksArr = this.callbacks.get(timeLapseMS);
            if (!callbacksArr) {
                this.callbacks.set(timeLapseMS, [callback]);
            } else {
                if (!callbacksArr.includes(callback)) {
                    callbacksArr.push(callback);
                }
            }
        };
    
        removeIdleTimeCallback = (callback, timeLapseMS) => {
            this.removeCallback(callback, timeLapseMS);
    
            let callbacksArr = this.callbacks.get(timeLapseMS);
            if (callbacksArr) {
                let index = callbacksArr.indexOf(callback);
                if (index !== -1) {
                    callbacksArr.splice(index, 1);
                }
            }
        };
    
        resetTimer = () => {
            for (let [timeLapseMS, callbacksArr] of this.callbacks) {
                callbacksArr.forEach(callback => {
                    // Clear the previous IDs
                    let timeoutID = this.timeoutIDs.get(timeLapseMS + callback);
                    clearTimeout(timeoutID);
    
                    // Create new timeout IDs.
                    timeoutID = setTimeout(callback, timeLapseMS);
                    this.timeoutIDs.set(timeLapseMS + callback, timeoutID);
                });
            }
        };
    }
    export const Scheduler = new _Scheduler();
    export const IdleTimeScheduler = new _IdleTimeScheduler();
    
    0 讨论(0)
  • 2020-11-21 12:39

    Well you could attach a click or mousemove event to the document body that resets a timer. Have a function that you call at timed intervals that checks if the timer is over a specified time (like 1000 millis) and start your preloading.

    0 讨论(0)
  • 2020-11-21 12:41

    Similar to Iconic's solution above (with jQuery custom event)...

    // 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)))
    
    0 讨论(0)
提交回复
热议问题