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 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.
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 <a href="http://developer.yahoo.com/yui/docs/YAHOO.env.ua.html">YAHOO.env.ua</a>
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.
–30–
Read more from the archive.