In my previous post, JavaScript Execution and Browser Limits, I described how the top 5 browsers determine when JavaScript code has run for too long and throw “unresponsive script” errors. It’s not practical to change the browser’s behavior and it may not always be possible to offload processing to the server. Fortunately, timers can help us execute long-running tasks without locking the browser.

What are timers?

JavaScript code, such as an individual function, can be set to run after a particular period of time has elapsed:

  • setTimeout(function, msec[, arg1 … argN])
    runs the named function after msec milliseconds have passed. The arguments, if any, are passed to that function.
  • setInterval(function, msec[, arg1 … argN])
    is similar to setTimeout except the function is called indefinitely every msec milliseconds.

Two other functions, clearTimeout() and clearInterval(), will cancel timer operations, e.g.


var timerID = setTimeout(myfunction, 500);
clearTimeout(timerID); // myfunction() will never be called

Note:

  1. setTimeout and setInterval are passed a reference to a function (there’s no parenthesis). The code setTimeout(myfunction(), 500); would run myfunction() immediately.
  2. The millisecond timings will rarely be accurate. They only specify that a function should run when the browser becomes idle after a specific period.
  3. Don’t rely on functions running in a specific order, e.g. setTimeout(f1, 50); setTimeout(f2, 50); — f2() could execute first.

Timer-based execution

Timed code isn’t run immediately, so the browser processing thread is released to perform other tasks. We can therefore split long processes into shorter chunks.

As a simple example, assume we want to run the functions f1(), f2() and f3() in order:


function ProcessThread(func) {
	var ms = 20;
	setTimeout(function() {
		func.shift()();
		if (func) {
			setTimeout(arguments.callee, ms);
		}
	}, ms);
}

ProcessThread([f1, f2, f3]);
note: func.shift()() ?!

That requires a little further explanation; func.shift() removes the first item from an array and returns it. That will be reference to a function, so we add parenthesis to execute it.

The statement is functionally identical to var f = func.shift(); f();

ProcessThread runs all the functions in the passed array, but waits 20ms between each. Any number of functions can be executed in sequence … assuming no individual function throws an “unresponsive script” error.

However, the most time-intensive code will probably be processing large arrays of data. In my next post, we’ll write more robust code to handle that type of operation.

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler

Free Guide:

How to Choose the Right Charting Library for Your Application

How do you make sure that the charting library you choose has everything you need? Sign up to receive this detailed guide from FusionCharts, which explores all the factors you need to consider before making the decision.


  • kissmyawesome

    arguments.callee is deprecated, so technically you should use a named function instead:
    function ProcessThread(func) {
    var ms = 20;
    setTimeout(function threadTimer() {
    func.shift()();
    if (func) {
    setTimeout(threadTimer, ms);
    }
    }, ms);
    }
    ProcessThread([f1, f2, f3]);

    • http://dt.in.th/ the DtTvB

      Though named functions may look better under some circumstances, arguments.callee is still there. :)

      It is in fact arguments.caller which is deprecated.

      • kissmyawesome

        I was convinced it was .callee, but you’re right – thanks for correcting me.

  • http://www.brothercake.com/ James Edwards

    I wrote about this a few years ago; might interest you — http://www.sitepoint.com/article/multi-threading-javascript

Learn JavaScript for free!
Free course: Introduction to JavaScript

Yours when you take up a free 14-day SitePoint Premium trial.