Archive for the ‘javascript’ tag
Lazy Loading JavaScript
Most of us know it’s best practice to load your JavaScript at the bottom of the page for performance reasons. The Yahoo! developer network explains the reasoning as follows:
It’s better to move scripts from the top to as low in the page as possible. One reason is to enable progressive rendering, but another is to achieve greater download parallelization.
What typically is not discussed, however, are the potential issues that arise when you follow this development rule-of-thumb. I hope to talk a little bit about this issue and a nice workaround that I like to employ to side step the landmines.
Uh-oh, JavaScript errors
Consider the following code block:
<body> <div> <a onclick="foo(); return false;" href="...">click me</a> </div> <script src="...defines foo..." type="text/javascript"></script> </body>
This complies with best practices for performance, but the astute developer will note that there is a small interval of time between the rendering of the a tag and the script tag. This means for that interval of time, a user could click the link and trigger an undefined function. That’s no good.
This problem is actually more pronounced than you might think. If you’ve ever watched users over the shoulder, you’ll know that some of them can be very click-happy (and they’ve every right to be). They don’t expect to wait for the full page to load before taking an action. Why should they? Isn’t that the whole point of progress rendering?
Also, this is a bug that tends to slip through the developer radars. We tend to wait for the entire page to load when we’re going through our code, save, refresh RAD cycles, probably because something inside us knows to wait for the page to “stabilize” before attempting to test that one feature we just coded up.
Wrong answer (sorta):
Purists will note that the best solution to this is to remove the onclick attribute from the HTML and instead load it during the onload (or DOMLoad) event within JavaScript. This frees up the HTML so it is just content and moves all the interactive stuff into JavaScript (the application layer) where it really belongs.
I’m actually not opposed to this reasoning, but for the purposes of shaving off every millisecond of lag, this solution will not work. There is still an interval of time between the rendering of the link and when the JavaScript attaches the onclick handler. Clicks during this time won’t register JavaScript errors, but they’ll either trigger the actual link or do nothing, depending on what you have set in the href attribute.
If you’re happy with that, great. If not, read on.
An example workaround:
Supposing that foo is a hefty function, we really do want to load it last on the page. This is especially common when foo is part of a larger framework or rides on top of said larger framework. This is because beastly libraries like prototype ought to be loaded last on the page if possible.
We can try the following:
<head> <script src="workaround.js" type="text/javascript"></script> </head> <body> <div> <a onclick="bar(); return false;" href="...">click me</a> </div> <script src="...defines foo..." type="text/javascript"></script> </body>
and in workaround.js:
function bar() { var closure = function() { if (typeof window.foo == 'function') { foo(); } else { setTimeout(closure, 100); } } closure(); }
Oooh, self referencing closures. That’s got to solve the problem just from sheer awesomeness, right? Let’s break down what’s going on.
Instead of calling foo directly, we’re calling bar, a function that we hope is lighter-weight than foo, since we’re allowing bar to be the exceptional bit of JavaScript that is loaded in the header. bar simply checks for the existence of foo every 100 milliseconds until it is loaded, at which point foo is called. Alternatively, onload could be employed, which is typically not as fast as polling every 100 milliseconds. Yet another alternative would be to employ DOMLoad, but you’d have to include extra JavaScript to get a cross browser friendly version.
But wait, there’s more
bar and foo are cute for example purposes, but we really want to generalize the concept.
Try this instead:
function safecall(func) { var closure = function() { if (typeof func == 'function') { func(); } else { setTimeout(closure, 100); } } closure(); }
The calling HTML should be:
<a onclick="safecall(foo); return false;" href="...">click me</a>
If you want to pass parameters, you’ll have to employ closures, not that you don’t want to.
<a onclick="safecall(function() { foo(arg1, arg2)}; return false;" href="...">click me</a>
Geez. JavaScript is powerful. The closures I mean – not the part where I just spent several paragraphs detailing what is essentially a hack.
Conclusion
We’ve defined a function safecall that can be defined as the sole script in the head tag which can be used to protect unloaded JavaScript that is sitting at the bottom of the page. Hopefully this will solve someone’s development headaches trying to fix all those new JavaScript headaches when someone in the office decided it would be cute to move scripts to the bottom of the page.
