Timeouts Explained

I went to the Bayjax Meetup held by Yahoo! yesterday. The theme of the speakers was how to improve the performance of your JavaScript. There were lots of good presentations that will hopefully be online soon. The presentation that was most useful for me was by Nicholas Zakas, from his book High Performance JavaScript. His talk inspired todays article, explaining how the timer works for timeouts in JavaScript.

First of all, it is important to understand that in a browser there is one thread managing both JavaScript execution and UI updates (the UI thread). This means that while JavaScript is executing the UI cannot update and vice-versa. If the UI thread is processing something, all new JavaScript and UI tasks are added to a queue, and executed in order.

Many developers believe that the setTimeout() and setInterval() functions will be executed when the timeout time has elapsed. However, this is not true, and most applications will have a little extra lag, before the timeout callback is executed. Instead of executing the callback immediately when the timeout expires, JavaScript adds the callback to the UI thread queue. Most of the time there are other tasks in the UI thread queue, which will be executed before the timeout callback. It is the UI thread queue that leads to the lag experienced when using timeouts.

Here is a simple example diagram showing how the UI thread works when clicking on a button:

a UI queue diagram

The UI thread first animates the button according to the browser design, then fires the JavaScript click event, then animates the button back to its original state. Next assume you have a 250ms timeout, but the end-user is interacting with the DOM just before the 250ms timeout expires. You might have a UI thread like this:

UI Thread

  1. … 250ms ellapsed
  2. UI animation
  3. click event
  4. focus event
  5. UI animation
  6. timeout callback <-- added at 250ms
  7. rest of the queue

So at 250ms the timeout callback is added to the UI queue, but the queue already has 4 other tasks to perform before executing the timeout callback. This is why JavaScript timeout callbacks do not execute precisely when the timeout expires.