0

I'm trying to create a small function that runs every minute, but if the user is still typing when the function is to be executed, delay the execution until the user stops typing.

I have read this and other relevant questions, but my problem is different in that it includes an already scheduled function execution through setTimeout()

I have tried resetting the timer if the user is still typing, but this only forces the function to run again multiple times.

var timer = null

runTimer()

$('body').on('keyup', ':input', function(e) {
    timer = setTimeout(runTimer, 400);
});

$('body').on('keydown', ':input', function(e) {
    clearTimeout(timer);
});

function runTimer() {
    setTimeout(function(){
        executeFunction();
    }, 60 * 1000);
}

function executeFunction() {
    console.log('Ran function')
    setTimeout(function(){
        executeFunction();
    }, 60 * 1000);
}

I want the function to be executed once every minute, delayed until user stops typing but reset the timer to one minute after being executed. Also using underscore.js is acceptable.

user2315641
  • 161
  • 3
  • 15
  • See https://lodash.com/docs/4.17.11#debounce – Nenad Vracar Jun 20 '19 at 09:24
  • 1
    `setTimeout(runTimer, 400)` instead of `setTimeout(runTimer(), 400)` – Satpal Jun 20 '19 at 09:24
  • @NenadVracar Yes, I know about debounce. My function is set to run irregardless of user typing. You can only use debounce if your function is to be executed by user typing, which is not true in my case. My function is set to be executed by setTimeout(). – user2315641 Jun 20 '19 at 09:29
  • This should help you https://stackoverflow.com/questions/3969475/javascript-pause-settimeout – Kobe Jun 20 '19 at 09:32
  • @Kobe Thanks, this may be a nudge in the right direction, although I don't want the time to be paused every time the user types, only when the setTimeout() is about to expire. – user2315641 Jun 20 '19 at 09:39

1 Answers1

1

You can use a isTyping variable to check whether any key is pressed, with setInterval to wait for isTyping to become false. When isTyping is false, run your function.

Something like this:

You can test by typing in the input fields. When you long press a key, the execution will stop and resume immediately when you release the key.

var isTyping = false;
var interval = null;

var count = 0; // demo only

$('body').on('keyup', ':input', function(e) {
    isTyping = false;
});

$('body').on('keydown', ':input', function(e) {
    isTyping = true;
});


runTimer();


function executeFunction(){
  console.log('Execute', count++);
  runTimer();
}

function runTimer(){
  // I change to 1 second for easy testing
  setTimeout(runExecute, 1 * 1000);
}

function runExecute(){
  /**
   * If not typing
   *   clear interval
   *   execute function
   * else, if interval is not set
   *   set interval
   * else
   *   do nothing, wait for user stop typing
   */
  if (isTyping !== true){
    clearInterval(interval);
    interval = null;
    executeFunction();
  } else if (!interval){
    interval = setInterval(runExecute, 4);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<input>

Note

Using keyup and keydown alone, isn't a good way to check whether a user is typing. See this question for a better implementation to check user typing.

yqlim
  • 6,898
  • 3
  • 19
  • 43
  • Thanks, indeed I need to change `keyup` and `keydown` to be a little more input-aware, but the problem of the question itself was solved. – user2315641 Jun 20 '19 at 10:23