Preloading images with sexy anonymous recursive functions

[2009-06-27]

I don't do a lot of Javascript, and I used to dislike Javascript. But nowadays, with frameworks like jQuery and Prototpe, Javascript is fun. And has some really sexy properties. Like recursive anonymous functions.

It's very common to update the document with HTML that is returned by an AJAX call. That works pretty well, except for the fact that the HTML is updated while the images are not fully loaded yet. And that looks ugly, especially when using effects to show or transform that HTML bit that you update.

So, I wanted to extract all the images from a piece of HTML and preload them, check if they are loaded, and update the page when all images are loaded.

So here's a very simple function that checks if an image is loaded.

// checks if an image is loaded
function isLoaded(im) {
  if (im.complete) { return true; }
  if (im.naturalWidth > 0) { return true; }
  return false;
}

And a recursive anonymous function, that receives an array of images. We check if these images are all loaded using the function 'isLoaded()', and update the HTML if so, or call itself anothertime if the images aren't loaded yet.

// anonymous recursive function that checks if images are loaded
// and updates html when all images are loaded.
var f = function(imgs) {
  // loop images
  var notCompleteYet = $A(imgs).reject(function(im) {
    return true == isLoaded(im);
  });
  if ($A(notCompleteYet).size() == 0) {
    // and update content when all images are loaded.
  }
  else {
    // or recurse
    setTimeout(arguments.callee, 100, imgs);
  }
}

And here is the tiny bit that does the Prototype AJAX call.

try {
  new Ajax.Request(url, {
    method: 'get',
    parameters: args,
    onSuccess: function(transport) {

      // create an element node form response text
      var html = transport.responseText;
      var node = new Element('div',
			     {id:'tmp-content',
                              style:'display: none;'},
			     ' ');
      node.update(html);

      // populate array with images to be preloaded
      var images = new Array();
      $A(node.select('img')).each( function(el) {
        im = new Image(84, 48);
        im.src = el.src;
        images.push(im);
      });

      // and check if all images are loaded, 
      // and update the HTML when they are all loaded.
      setTimeout(f, 500, images);
      node = null;
    },
    onFailure: function() {
      throw('Ajax call failed');      
    }
  });
}
catch(e) {
  // error handling
}

Enjoy playing with it ;-)

 

Comments

_

Want to leave a msg?

_

 

No comments yet...