51

I'd like to know how to achieve: generate a random number after a random number of time. And reuse it.

function doSomething(){
     // ... do something.....
}

var rand = 300; // initial rand time

i = setinterval(function(){

     doSomething();
     rand = Math.round(Math.random()*(3000-500))+500; // generate new time (between 3sec and 500"s)

}, rand); 

And do it repeatedly.

So far I was able to generate a random interval, but it last the same until the page was refreshed (generating than a different time- interval).

Thanks

Akkuma
  • 2,215
  • 3
  • 16
  • 21
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313

6 Answers6

111

Here is a really clean and clear way to do it:

http://jsfiddle.net/Akkuma/9GyyA/

function doSomething() {}

(function loop() {
    var rand = Math.round(Math.random() * (3000 - 500)) + 500;
    setTimeout(function() {
            doSomething();
            loop();  
    }, rand);
}());

EDIT:

Explanation: loop only exists within the immediately invoked function context, so it can recursively call itself.

Akkuma
  • 2,215
  • 3
  • 16
  • 21
  • 1
    Nice solution, but it requires some change if you want to be able to remove "interval" in a while. – topright gamedev Mar 02 '14 at 15:36
  • 3
    @toprightgamedev if you want to stop looping, simply place an if statement around the setTimeout with the logic you need. – Akkuma Oct 22 '15 at 19:00
  • Sorry to dig up this answer so many year after but I have a question : won't you have a stack of execution context that keep increasing without end with this solution ? – jobou May 23 '17 at 10:52
  • I found a nice explanation on why it does not create a stack of execution context : https://stackoverflow.com/a/13506904/1951430 – jobou May 23 '17 at 11:00
  • @jobou it does stack execution contexts. You're right. – user3871 Oct 17 '18 at 04:51
  • what is the purpose of `(3000 - 500)) + 500`? is this supposed to make it more random? – oldboy Oct 16 '20 at 11:40
14

Here's a reusable version that can be cleared. Open-sourced as an NPM package with IntelliSense enabled.

Utility Function

const setRandomInterval = (intervalFunction, minDelay, maxDelay) => {
  let timeout;

  const runInterval = () => {
    const timeoutFunction = () => {
      intervalFunction();
      runInterval();
    };

    const delay = Math.floor(Math.random() * (maxDelay - minDelay + 1)) + minDelay;

    timeout = setTimeout(timeoutFunction, delay);
  };

  runInterval();

  return {
    clear() { clearTimeout(timeout) },
  };
};

Usage

const interval = setRandomInterval(() => console.log('Hello World!'), 1000, 5000);

// // Clear when needed.
// interval.clear();
jabacchetta
  • 45,013
  • 9
  • 63
  • 75
7

Something like this should work - use setTimeout() instead so you can set a new random value each time:

function doSomething() {
    alert("doing something");
}

function init() {
    var myFunction = function() {
        doSomething();
        var rand = Math.round(Math.random() * (3000 - 500)) + 500; // generate new time (between 3sec and 500"s)
        setTimeout(myFunction, rand);
    }
    myFunction();
}

$(function() {
    init();
});

Working jsFiddle here.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
3

Just setup interval each time you rand (and clear it first)

function doSomething(){
     // ... do something.....
}

var i;
var rand = 300;

function randomize() {
    doSomething();
    rand = Math.round(Math.random()*(3000-500))+500; 
    clearInterval(i);
    i = setInterval('randomize();', rand);
}

i = setInterval('randomize();', rand);

or try using setTimeout (and setting again after randing)

Nazin
  • 827
  • 3
  • 16
  • 31
1

Just throwing my hat in the ring

    var keepLooping = true;
    (function ontimeout(){
        if(keepLooping){
            doTheAction();
            setTimeout(ontimeout, Math.random() * 100);
        }
    })();

depends if you want to put doTheAction() inside the setTimeout callback or not. I think it's fine to put it before/outside. If you want the initial delay, then put it inside, if not, put it outside for simplicity.

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
0

I am using this:

function setRandomInterval(intervalFunction, minDelay, maxDelay) {
  let outerFunction = () => {
    let delay = Math.floor(Math.random() * (maxDelay - minDelay + 1)) + minDelay;
    let timeout = setTimeout(outerFunction, delay)
    intervalFunction(timeout)
  }
  outerFunction()
}

Usage:

let start = performance.now()
let i = 1
setRandomInterval((timeout) => {
  let end = performance.now()
  console.log("Run count", i)
  console.log("Random time elapsed", (end - start) / 1000)
  start = end
  i++
  if (i > 5) {
    clearTimeout(timeout)
  }
}, 500, 5000)
Pankaj
  • 37
  • 7