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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.