I talked before about using an object
element to load scripts and styles without executing/applying them to the current document. And this is nice for preloading assets - faster and less error-prone than simple inclusion if the document or iframe.
But what about preloading assets (scripts) and then executing them on the current page? Turns out it works just fine, like so:
- create an
object
element and point itsdata
to the JavaScript file to be loaded - listen to the
load
event of theobject
- once loaded, create a
script
element and point itssrc
to the file, which would be already cached - optionaly, execute a callback function once the
script
element is properly inserted into the DOM
Something like this:
function yield(file, callback) { var o = document.createElement('object'); o.data = file; o.width = 0; o.height = 0; o.onload = function() { var s = document.createElement('script'); s.src = file; s.onload = function() { callback(o, file); }; document.getElementsByTagName('head')[0].appendChild(s); }; document.body.appendChild(o); }
But, but.. why?
Well, first off it's yet another way to load JavaScript files asynchronously, in a non-blocking fashion. And that's a good thing. Async = win. This method sure beats others such as document.write (eek) or iframe. It has advantage over XHR because there's no same-domain restriction. DOM include is probably the only simpler and more robust method, but there are cases where the object element might be preferable.
DOM-included scripts in FF and Opera always execute in order. That's cool, but sometimes you may prefer out of order async execution. Whenever a script is ready - go! Or sometimes you may prefer if the script is not executed at all! That may sound odd (why would I load it if I don't want to execute it?) but I have a use case - auto-complete. When your data source is on another domain and you can't use XHR, then JSON-P would be the way to go. But the network is a jungle and anything can happen.
Say you make requests for auto-complete suggestions with queries "h", "he", "hel", "hell", "hello". For some reason "hel" is really slow and you already have the results for "hell" and even "hello". What you want to do is just kill and cancel the "hel" response, who cares - it's outdated already. But if you use JSONP in FF and Opera "hel" will block the others. If order is not preserved it might be even weirder - you update the page with the "hello" suggestion and then "hel" finally arrives and updates the suggestion once again. Fail.
Using the object
element approach you can keep a list of requests that went out and simply choose to ignore previous requests if newer responses are already there.
I have a test case even.
Small print
This technique assumes that the scripts you load don't have any headers preventing caching, otherwise they'll be requested twice.
My example code above ignored IE completely, but you can easily make it work, either using new Image()
instead of object
or tweaking the object with height and width of 1 as shown in the old article. Or you can use the trick that LABjs uses (I think) which is to DOM-insert a script element with invalid type such as cache/javascript
. Also you need to listen to onreadystatechange instead of load event when inserting a DOM element.
Comments? Find me on BlueSky, Mastodon, LinkedIn, Threads, Twitter