I have been spending some time in jQuery chat lately, and something that comes up fairly often is the desire to repeat an action every n milliseconds. “No problem”, many will say. “Just use setInterval.” I consider this to be terrible advice.

Reason #1: setInterval ignores errors.

setInterval has a nasty habit of not paying any attention to whether or not the code it calls generates errors. This means that if, for some reason, an error occurs in part of the code that is called by setInterval, it will continue to call that code over and over again. Demo

Reason #2: setInterval does not care about network latency.

Let’s say you are polling a remote server for any new data on a fixed interval using AJAX. (Note: If you are doing this, you are probably doing it wrong; use backoff polling instead.) For some reason (server overload, temporary network connectivity loss, Slashdot effect, satellite/dial-up user, whatever), these requests are taking longer to complete than you thought they would. setInterval doesn’t care. It will continue firing those requests off, over and over again, until your client’s network queue is filled up with AJAX calls. Demo

Reason #3: setInterval does not guarantee execution.

Unlike setTimeout, there is no guarantee that an interval will actually execute when you ask it to. If the function you call on an interval takes too long to complete, some invocations will simply end up being dropped. Demo

The solution is simple: setTimeout

Instead of using setInterval, make the function call itself using setTimeout at an appropriate moment. In both of the above demos, function a does it wrong using setInterval, and function b does it more properly with setTimeout.

But what if I absolutely need the event to occur at the same interval every time?

If you want to ensure that your events are occurring on an ‘even’ interval, you can calculate the difference between your intended delay and the amount of time the last call took to complete and adjust your setTimeout delay appropriately. It is important to note, however, that JavaScript timers are not high-precision. You will never ever get absolutely even intervals, even if you use setInterval, for a variety of reasons (garbage collectors, the fact that JavaScript is single-threaded, solar flares, etc.). In addition, all current browsers will clamp the minimum timeout value to somewhere between 4ms and 15ms. So don’t worry too much about the difference!

Update 2011-03-01: I added the 3rd reason I inadvertently omitted from the original article.

4 Responses to this post

  1. I agree whole heartedly. This is one of these things many people never considers when they want that specific behavior. I've explained this a few times to colleagues and friends, and now I got a blog post that will explain this in detail. Thanks :)

  2. You can always check for errors and call clearInterval() if needed.

  3. Yes, You can always check for errors and call clearInterval() if needed. Why Not?

  4. Checking for errors is non-trivial if you are performing any asynchronous action inside your interval, and is likely to lead to some pretty gross code. Also, try/catch blocks break stack traces in IE, even if you re-throw the error later.

    One thing I forgot to mention in this article is that you aren’t even guaranteed that your intervals will fire; if you are executing a slow, blocking function through setInterval and it doesn’t return before the next interval is due, some of them will be silently dropped by the browser. It’s just not a good idea.