Alternatives to image.onload

Recently I’ve been working on a few web projects that involve preloading images in the background. This needs to happen for 2 reasons; to adjust containers for images of differing dimensions, and to give the user a nicer experience.

A quick Google shows that there is no native way to achieve this across all browsers. The onload event handler works in some, but even then it can be buggy. I’ll show you two workarounds I use.

Timers

The simplest technique involves placing an image element off-screen with CSS, and storing its initial height (with no src attribute value, this should be 0). To preload an image, we create a timeout function that measures the element height at a certain interval, call it, then apply the src value.

var img=document.getElementById('img');
var h=img.offsetHeight;
setTimeout(function(){
	if (img.offsetWidth!=h) alert(img.offsetWidth, img.offsetHeight);
	else setTimeout(arguments.callee,100);
	});
img.src='http://localhost/ignite/test.jpg';

The main problem I see with this is the use of the timer. If the image doesn’t exist, or the server is unavailable, the timer will continue to run with no way of cancelling. You could build in a maximum duration for the timer, but load times could vary a lot depending on the image filesize and the user’s available bandwidth.

Iframes

Instead, I use this technique. Rather than an image element, I create an iframe (again, off screen or otherwise hidden with CSS). When I need to preload an image, I point the iframe’s src at the following PHP script:

<html>
<head>
<style type='text/css'>
* {padding:0px; margin:0px}
</style>
<script type='text/javascript'>

window.onload=function(){
	var w=document.body.scrollWidth;
	var h=document.body.scrollHeight;

	(function(){	// capture errors due to the top window not being loaded yet
		try{
			<?=$_GET["callback"]?>(w,h,'<?=$_GET["img"]?>');
			}
		catch(e){
			setTimeout(arguments.callee,100);
			}
		})();
	};

</script>
</head>
<body>
<img id='img' src='<?=$_GET["img"]?>' />
</body>
</html>

Pass the image URL and callback string in the parameters, like this:

imageLoader.php?img=test.jpg&callback=window.parent.foo

This outputs a simple HTML page containing the image. Once the image is loaded, the window’s onload event handler fires, allowing us to pass back the image’s width, height and URL to the specified callback function in the parent window.

That’s all, folks

I prefer this second technique as it avoids using setTimeout. Neither is perfect, but they certainly do the trick.

Posted October 3rd, 2009 in JavaScript.

Leave a response: