Nasty Race Condition Between Js and Load Events

I received an email from a client asking me to look into some problems in his site. The problems are unrelated to this post, but what I found when I visited the site was rather unexpected. When I worked on this site last time I was on “vacations” back in Mexico, and truth be told, the internet connection I get there is terrible. I think that is why I did not notice the problem that I noticed today.

As I loaded the site, I noted the images where not loaded. I thought they might be missing, so I went on firebug HTML inspector, and found out that the images where loaded, but they were hidden via CSS using the visibility property. I remembered then that I had implemented a form of simulated lazy loading to make the site seem faster. As I always say, if you can make it faster, make it feel faster. This artificial lazy loading did make the site feel faster, but it generated a problematic race condition.

The problem is that sometimes the images would load faster than the javascript file. This is because the javascript file is loaded after the images in the HTML code. The code that hid the images looked something like this:

var images = b('img');//get all the images
images.css('visibility', 'hidden');//hide them
images.load(function(){//when loaded, show them back again
    B(this).css('visibiity', 'visible');
});

The problem, as you may have already guessed, is that the event handler was added after the event had been fired, which caused the images to remain hidden.

There are at least a few ways to fix this problem, but I won’t go into much detail about that since it is not the purpose of this post. The purpose is, rather than fixing the problem, identifying it. Sometimes we don’t realize what type of nasty race conditions our code can create. I think this also demonstrates that adding your js on the footer is not always such a good idea. The best solution in this case would be to check if each particular image has finished loading, if so, leave it untouched, if not, hide it and add the event handler. I think it is the best way to solve it because it still allows for javascript to be added at the end of the document. To detect if the image is loaded, we could use the complete image property. I have not tested this yet, but it could work.

Read more about the image DOM element: https://developer.mozilla.org/en-US/docs/DOM/HTMLImageElement