2

What would be a good approach to best implement setInterval using setTimeout?

Take into account that the mocked setInterval should be able to be "cleared".

9
  • stackoverflow.com/help/self-answer Commented Jun 3, 2018 at 9:48
  • Why do you want to do that? What refrains you form using the built-in implementation? Commented Jun 3, 2018 at 9:51
  • 1
    because I was challenged by someone, for fun. not all programs have real-life purpose, and it's alright to create things for pure fun. Commented Jun 3, 2018 at 9:52
  • In that case would you accept this Q/A as a dupe? There the challenge was even more fun. Or even this one which shows an implementation with a real use case. Commented Jun 3, 2018 at 9:54
  • Of "implementing your own timing function with no real goal". Commented Jun 3, 2018 at 9:59

5 Answers 5

5

Here the intervalId is the reference object that contains the timeoutId. The reference object changes every time the setTimeout is called recursively.

const _setInterval = (callback, delay) => {
  const timerRef = { id: null };
  const timeout = () => {
    timerRef.id = setTimeout(() => {
      callback();
      timeout();
    }, delay);
  }
  timeout();
  return timerRef;
};

const timerRef = _setInterval(() => {
  console.log("Callback");
}, 1000);

setTimeout(() => {
  clearTimeout(timerRef.id);
}, 5000);
Sign up to request clarification or add additional context in comments.

Comments

4

To mock setInterval accurately, ons has to mock clearInterval too:

{
  const intervals = new Map();

  function setInterval(fn, time, context, ...args) {
    const id = Math.floor(Math.random() * 10000);
    intervals.set(id, setTimeout(function next() {
       intervals.set(id, setTimeout(next, time));
       fn.apply(context, args);
    }, time));
    return id;
  }

  function clearInterval(id) { 
    clearTimeout(intervals.get(id));
  }
}

And you can use it as always:

 const interval = setInterval(console.log, 100, console, "hi");

clearInterval(interval);

1 Comment

I might be misreading (on a phone rn) but I think your implementation will make it impossible to clear the interval from the callback.
1

I have a promise based solution without recursion :)

function setInterval1(fn, time) {
    let check = { check: true };
    (async function () {
        for (let i = 0; i < Number.POSITIVE_INFINITY && check.check; i++) {
            await new Promise((resolve) => {
                setTimeout(() => { fn(); resolve(true); }, time);
            });
        }
    })();
    return check;
}

let check = setInterval1(() => console.log('hi'), 1000);

function clearInterval1(check) {
    check.check = false;
}

setTimeout(() => { clearInterval1(check) }, 4000)

Comments

0

Below code creates a mock implementation of setInterval using setTimeout

function interval(cb, ms){
  var a = {
    clear : function(){
      clearTimeout(a.timer)
    }
  };
  (function run(){
    cb();
    a.timer = setTimeout(run, ms);
  })();
  
  return a;
}


var myInterval_1 = interval(()=>{ console.log(1) }, 1000); // create an "interval" 
var myInterval_2 = interval(()=>{ console.log(2) }, 1000); // create another "interval" 

// clear the first interval
setTimeout(()=>{ myInterval_1.clear() }, 4000)

8 Comments

That doesn't respect the specs at all.
@Kaiido - what specs? what are you talking about? this works, why the downvote?
Because setInterval implementation is specified by some documents, and that you don't apply these specifications, i.e adding a fool-guard against infinity loops.
you are taking all this too seriously. I am only having fun with javascript, a language which I love and code for the last 13 years.
Sorry, but I don't see the fun in this implementation at all.
|
0

Another form to append it in window object and mimic global setInterval and clearInterval

(function (window) {
  const idMap = {};
  window.customSetInterval = (cb, duration) => {
    let x = null;
    const loop = (cb) => {
      const y = setTimeout(() => {
        cb();
        loop(cb);
      }, duration);
      if (!idMap[x]) {
        x = y;
      }
      idMap[x] = y;
    };
    loop(cb);
    return x;
  };
  window.customClearInterval = (x) => {
    clearTimeout(idMap[x]);
  };
})(window);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.