Skip to content

ara pehlivanian

Web Standards, Web Culture, Web Everything.™

On Event Throttling

The Problem

Recently I had to use the window object’s onresize event in a project I was working on. I needed it in order to reposition some elements on a page whenever the browser’s window size changed. The trouble was, the function was relatively intense and was causing IE to choke. The reason? Different browsers fire the event at different intervals. In Firefox, it fires only once the user stops resizing the window. In IE, it fires continuously while the user is resizing the window. This of course, meant that IE was trying to run my function once every millisecond or so.

window.onresize = function () {
    // Do something, just nothing intense for IE's sake
}

The Solution

The solution is event throttling, something that Christian Heilmann had mentioned to me once before. Here’s how my flavour of it works:

var timeoutId;

/**
 * Throttles a resize event.
 * @param {Function} fn  The function to execute
 */
function throttleResize(fn) {
    window.onresize = function () {
        window.clearTimeout(timeoutId);
        timeoutId = window.setTimeout(
            function () {
                fn.call();
            },
            250);
    };
}

/**
 * Just a function to fire on resize
 */
function doSomething() {
    alert("I've been resized!");
}

/**
 * Set up the throttle
 */
throttleResize(doSomething);

As you can see, I’m setting the onresize event for the window object as you normally would. The difference is, I’m only calling my doSomething function after a 250 millisecond delay. The way I do this is to simply use the window object’s setTimeout method, with a catch. The trick is to clear the setTimeout method I’d previously set before setting it again. This effectively resets the timer every time the onresize event fires until it’s done firing.

Getting Fancy

The continuous triggering of the onresize seems to be limited to IE, though I think I saw it in Safari 3 Beta for Windows as well. At any rate, this can be managed with an if/else block that checks to see which browser is running the code and either wrapping the function with the timer or not. I’ve found YUI’s YAHOO.env.ua works quite well at identifying the browser. But for simplicity’s sake, I’ll manually verify if we’re in Firefox or not for this example. Here’s the same code with the differentiation applied:

var timeoutId;

/**
 * Throttles a resize event.
 * @param {Function} fn  The function to execute
 */
function throttleResize(fn) {
    if (navigator.userAgent.indexOf("Gecko") === -1) {
        window.onresize = function () {
            window.clearTimeout(window.timeoutId);
            window.timeoutId = window.setTimeout(
                function () {
                    fn.call();
                },
                250);
        };
    } else {
        window.onresize = function () {
            fn.call();
        };
    }
}

/**
 * Just a function to fire on resize
 */
function doSomething() {
    alert("I've been resized!");
}

/**
 * Set up the throttle
 */
throttleResize(doSomething);

It’s important to note that if your onresize event handler modifies the height of the body element, you’ll be inadvertently re-triggering the onresize event in IE. You can read more about this phenomenon and how to deal with it in Jonathan Snook’s post, IE Fires Onresize When Body Resizes.

Sphere: Related Content

Buy my book

The Art & Science of JavaScript / SitePoint
The Art & Science of JavaScript

Advertisement

Firebug - Web Development Evolved

Advertisement

Leave a comment

Note: First time comments will be held for moderation as an added anti-spam measure.

Skip to navigation

More stuff by Ara elsewhere on the web

    Snook Approved!

    © 2005-2008, Ara Pehlivanian.

    Stock photography courtesy stock.xchng. This site uses Akismet to catch spam (54,754 caught since May 2006) is hosted by DreamHost and powered by WordPress.