tag:blogger.com,1999:blog-8112154.post8288633186397270993..comments2024-03-27T17:18:31.430+05:30Comments on blog.rakeshpai.me: Downloading JavaScript Files in ParallelRakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.comBlogger21125tag:blogger.com,1999:blog-8112154.post-1647751334710002752023-02-23T17:19:47.215+05:302023-02-23T17:19:47.215+05:30I gotta bookmark this website it seems very benefi...I gotta bookmark this website it seems very beneficial. Thank you! <a href="https://www.personaltrainersherwoodpark.com/" rel="nofollow">https://www.personaltrainersherwoodpark.com/</a>Guesthttps://www.blogger.com/profile/11889615443281459134noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-31113242919901761492011-10-04T17:00:12.649+05:302011-10-04T17:00:12.649+05:30Hello, great work but the script doesnt work with ...Hello, great work but the script doesnt work with firefox. Can you update it please? And is it possible to add a non blocking javascript ?billhttp://www.keedeo.comnoreply@blogger.comtag:blogger.com,1999:blog-8112154.post-18955854189049004222011-01-20T02:02:38.792+05:302011-01-20T02:02:38.792+05:30WARNING: The FF and Opera behavior upon which the ...WARNING: The FF and Opera behavior upon which the execution order preservation is built is BROKEN IN FF 4 and Opera 10+ <br /><br /><br />You can accomplish parallel loading in Internet Explorer without the need for document.write using onload-chaining. Much like an Image() element, IE will fetch the URL assigned to the SRC attribute of a script even if it's not yet inserted into the DOM. Instead of inserting the elements immediately, add them to a queue. Then add an onreadystatechange handler that pulls the next script in the queue and loads it. <br /><br />http://digital-fulcrum.com/webperf/orderedexec/<br /><br />Vote for these two bugs to have the same behavior added to FF and WebKit<br /><br />https://bugs.webkit.org/show_bug.cgi?id=51650<br /><br />https://bugzilla.mozilla.org/show_bug.cgi?id=621553Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-8112154.post-14342424941489383432010-08-27T05:27:22.361+05:302010-08-27T05:27:22.361+05:30Hi Everyone,
Please how can I use this code on a...Hi Everyone, <br /><br />Please how can I use this code on a WordPress site to make the scripts load in Parallel? <br /><br />Thanks, <br /><br />Richie.Mountain Bike Storehttp://www.onlinebikestores.com/noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-13078181698863797992010-02-25T17:05:26.089+05:302010-02-25T17:05:26.089+05:30A long....and interesting discussion. I just have ...A long....and interesting discussion. I just have and idea to add...<br />If we divide the design into two components loader and initializer we can not only load all the required scripts in parallel and also fire a custom event that can fire a callback or load another script. <br /><br />That way, for example I need to initialize 2-3 image galleries on a screen depending on some condition I can load the script to create the galleries and after it has loaded I can fire initializer for the galleries.<br /><br />YUI has a loader incorporated in it that does fire a load completed event. <br />http://developer.yahoo.com/yui/yuiloader/<br /><br />IE should support on ready state change event, FF supports onload for Scripts as well as LINK tags.<br />(just mentioning)<br /><br />Another interesting scenario which can come up as a direct inference - Does it make sense to create a script (with minimal performance hit) that can manage all the JS and CSS files loaded on the browser at a time. Can this library design have capabilities to reload on demand or maybe also remove scripts?<br /><br />Lab.js http://labjs.com/ is also an interesting example on these lines<br /><br />Any comments/views on this thought process will be accepted.<br /><br />PS. I think I need to mention here that I am not trying to criticize any approach in any way. I myself used the code (with some tinkering ) that Rakesh showed here in a released project.Mohahttps://www.blogger.com/profile/06759418078245783643noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-8267166436084522792009-08-06T01:59:41.802+05:302009-08-06T01:59:41.802+05:30We're finding that on FF, the append to head m...We're finding that on FF, the append to head mechanism fails if the server drops the javascript request. In that case, the javascript will hang the browser. You can test this by doing a parallel download of a javascript file and then set iptables on the server to drop requests from your browser on both the input and output chains.Adam Carlsonnoreply@blogger.comtag:blogger.com,1999:blog-8112154.post-74790317677808237382009-07-31T15:55:59.733+05:302009-07-31T15:55:59.733+05:30That's simply great!That's simply great!tbela99http://www.mboablog.comnoreply@blogger.comtag:blogger.com,1999:blog-8112154.post-28793217631641232732009-07-29T17:47:13.328+05:302009-07-29T17:47:13.328+05:30Yesudeep, that is not my design goal - just a cons...Yesudeep, that is not my design goal - just a consideration. The design goal is to make script downloads in parallel across domains and preserve script execution order. The script does that well across all browsers I've tested. It doesn't give undefined symbol references at all. Not meaning to flame at all, but your script doesn't achieve all of this.<br /><br />In particular, your script doesn't preserve script execution order, giving rise to the possibility of undefined symbol errors if your scripts are interdependent.<br /><br />BTW, the 4k from your results is not minor savings at all. It all adds up VERY quickly, especially at the scale at which these kind of optimizations are required in the first place.<br /><br />Since you still mention speed of execution, I would love to see some benchmark pointing out the difference in a realistic case of say max 10 files.Rakesh Paihttps://www.blogger.com/profile/00328152982823663876noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-81810275906022157222009-07-29T17:08:48.997+05:302009-07-29T17:08:48.997+05:30I agree, we have different design goals.
While you...I agree, we have different design goals.<br />While you're trying to minimize the space used, I'm being more focused on the speed of execution while not losing too much out on space.Yesudeephttps://www.blogger.com/profile/01263304214825004452noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-43672364619439009922009-07-29T17:07:01.115+05:302009-07-29T17:07:01.115+05:30About gzip encoding:
-rw-r--r-- 1 yesudeep yesude...About gzip encoding:<br /><br />-rw-r--r-- 1 yesudeep yesudeep 652 2009-07-29 16:51 rakesh.js<br />-rw-r--r-- 1 yesudeep yesudeep 513 2009-07-29 16:58 rakesh-min.js<br />-rw-r--r-- 1 yesudeep yesudeep 338 2009-07-29 16:56 rakesh-min.js.gz<br />-rw-r--r-- 1 yesudeep yesudeep 659 2009-07-29 16:54 yesudeep.js<br />-rw-r--r-- 1 yesudeep yesudeep 513 2009-07-29 16:58 yesudeep-min.js<br />-rw-r--r-- 1 yesudeep yesudeep 334 2009-07-29 16:56 yesudeep-min.js.gz<br /><br />The only difference is I've removed t[sa] references, removed the definition for sa, and used .setAttribute directly instead. :-)<br /><br />The same size when only minified using the YUI Compressor.<br /><br />An impressive 4 bytes shorter when gzipped! Ok, kidding. Not so impressive, but in a large script this can make a huge difference.<br /><br />var s = [<br /> "/javascripts/script1.js",<br /> "/javascripts/script2.js",<br /> "/javascripts/script3.js",<br /> "/javascripts/script4.js",<br /> "/javascripts/script5.js"<br />];<br /><br />var sc = "script", <br /> tp = "text/javascript", <br /> doc = document, ua = window.navigator.userAgent;<br />for(var i=0, l=s.length; i<l; ++i) {<br /> if(ua.indexOf("MSIE")!==-1 || ua.indexOf("WebKit")!==-1) {<br /> doc.writeln("<" + sc + " type=\"" + tp + "\" src=\"" + s[i] + "\" defer></" + sc + "<");<br /> } else {<br /> var t=doc.createElement(sc);<br /> t.setAttribute("src", s[i]);<br /> t.setAttribute("type", tp);<br /> doc.getElementsByTagName("head")[0].appendChild(t);<br /> }<br />}<br /><br />This explains GZip encoding:<br />http://code.google.com/speed/articles/gzip.html<br /><br />And I can pretty much see the same example in there that I wrote about earlier.Yesudeephttps://www.blogger.com/profile/01263304214825004452noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-14041233388453222172009-07-29T16:37:24.284+05:302009-07-29T16:37:24.284+05:30Yesudeep,
You are talking about the benefits of r...Yesudeep,<br /><br />You are talking about the benefits of readability vs. compression, and in itself it's a worthy topic of discussion. I chose to compromise on readability a little so that it can compress better. Since sa is now just a variable, and not a public member of an element, t[sa] compresses better with say shrinksafe since it doesn't have to preserve global symbols with respect to method references.<br /><br />This script is about on-the-wire performance optimization, and I didn't want a bootstrap itself to add too much baggage. Gzip is a layer that is added later, and will give its benefits in either case. Depending on the context, I generally disagree with relying on gzip as a crutch for handling code bloat.<br /><br />[digression]<br />IIRC, Gzip's Hoffman algorithm is based on the frequency of repetition of characters <em>in the English alphabet</em>, and not on the frequency or number of characters in the file being compressed. This is why binary files don't compress well with Gzip. Gzip is a one pass algorithm. If it had to take into account multiple occurrences within the same file, it would at least be a two pass algorithm. So, repetition of text in the file in itself doesn't help Gzip one bit. Correct me if I'm mistaken about this.<br />[/digression]<br /><br />You are right again about the getElementsByTagName() call being a loop invariant. However, you are probably being too critical about the performance implications. Firstly, getElementsByTagName is not an expensive a call at all - it's implemented natively and doesn't cause any browser redraw behavior. The appendChild does do a DOM manipulation, but it can't be avoided. (Well, it can be batched up for performance, but that increases code size as well. It's a fine line.)<br /><br />Besides, and like I said before, if you are doing more than a very few script includes, you are doing it wrong. I would say that even iterating 5 times is excessive. The benefits of optimizing a loop which will run so few times and does so little within it is of very diminishing value. I'd err on the side of compact concise code.<br /><br />About the use of document.write vs. script tag injection, I wonder if you got the chance to look at <a href="http://www.slideshare.net/souders/sxsw-even-faster-web-sites" rel="nofollow">Steve Souders slides</a> that I have linked above. Check out the discussion on (and leading up to) slide 25. You should get a sense of the reason I made the choice to browser sniff. Look especially at the parallel download capabilities and the abilities to preserve script execution order.<br /><br />Hope this helps.Rakesh Paihttps://www.blogger.com/profile/00328152982823663876noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-4845432651197208622009-07-29T14:30:46.070+05:302009-07-29T14:30:46.070+05:30Hi Rakesh,
I'm pretty sure you have your reas...Hi Rakesh,<br /><br />I'm pretty sure you have your reasons to disagree, and that's appreciated.<br /><br />Certainly, you wouldn't want to include a ton of scripts into your code. Minimizing the number of HTTP requests made by combining scripts is surely a production tip. However, when you are testing code on a development server, it really doesn't make sense to have all of them combined as debugging them then becomes painful (ref. error foobar on line 9456 in entire.library.js or line 1 in entire.library.min.js). <br /><br />Anyway, including a lot of scripts wasn't my point in the blog post if you noticed.<br /><br />Factoring out loop invariants and caching access to global variables does speed up code and to my mind, there's no reason to not do this. As for the number of bytes consumed over-the-wire, do you really think t[sa] makes a difference for example? If you're using gzip compression to serve your script files, and I'm sure you would, t.setAttribute, t.setAttribute, t.setAttribute, ... becomes a non-issue. There don't appear to be any benefits doing that, for example.<br /><br />For arguments sake, if you're using a UNIX or Linux, you can try sticking this list of words into a file:<br /><br />Apple<br />Google<br />Microsoft<br />Orange<br />Mango<br />Tomato<br />Mongo<br />China<br />Charlie<br />Delta<br />Gamma<br />Beta<br /><br />and run `gzip filename.txt` on that.<br /><br />Now try that on this input:<br /><br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br />Apple<br /><br /><br />I'm pretty sure you'll see a large difference.<br /><br />var sa = 'setAttribute';<br />t[sa](foo, bar); is surely harder to read than t.setAttribute(foo, bar);. Don't you agree? :-)<br /><br />Additionally, look at this line:<br /><br />doc.getElementsByTagName("head")[0].appendChild(t);<br /><br />This is inside a loop. doc.getElementsByTagName("head")[0], again is a loop invariant (it fetches the same DOM element per iteration and DOM is pretty damn slow!), and can be pretty easily factored out of it.<br /><br />Also, which version of Firefox or Opera do you see doesn't download scripts in parallel when we use document.write()? As I said, I do not have access to to Firefox 2.0/Opera 9.x or earlier and IE. With the latest release of both browsers, document.write() does cause the browser to fetch scripts in parallel.<br /><br />I'd appreciate any help with this and would be more than happy to document them and incorporate them into my version as well. Thanks for taking the time for answering. :-)<br /><br />Cheers,<br />Yesudeep.Yesudeephttps://www.blogger.com/profile/01263304214825004452noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-15149576919058647822009-07-29T13:32:37.731+05:302009-07-29T13:32:37.731+05:30Yesudeep made a couple of points on his blog post ...Yesudeep made a couple of points on his <a href="http://yesudeep.wordpress.com/2009/07/29/making-the-browser-download-scripts-in-parallel/" rel="nofollow">blog post</a> about this code, almost all of which I disagree with. However, he made two excellent points about the loop. (1) That the scope chain lookup requires to go up to the global scope, and (2) that there are loop invariant computations being made in the loop.<br /><br />I have made code changes to address point 1 above, by caching global scope variables in the local scope to reduce the scope chain lookup, making the loop theoretically faster. I am currently not fixing 2 since it not only increases code size, it also reduces readability.<br /><br />If you are looping too much, it means you have a lot of JS to files to download, which itself you should rethink.Rakesh Paihttps://www.blogger.com/profile/00328152982823663876noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-35318694074152045402009-07-29T10:55:57.589+05:302009-07-29T10:55:57.589+05:30It's not that Firefox doesn't support it. ...It's not that Firefox doesn't support it. It's that it doesn't cause the downloads to happen in parallel.Rakesh Paihttps://www.blogger.com/profile/00328152982823663876noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-50009919263894781352009-07-29T05:47:06.271+05:302009-07-29T05:47:06.271+05:30Hi Rakesh,
Why are you sniffing for browsers?
Doe...Hi Rakesh,<br /><br />Why are you sniffing for browsers?<br />Does Firefox not support document.write()?<br /><br />Cheers,<br />Yesudeep.Yesudeephttps://www.blogger.com/profile/01263304214825004452noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-7588248251541438412009-07-17T14:02:40.702+05:302009-07-17T14:02:40.702+05:30Hey Prashanth,
Not sure if your suggestion makes ...Hey Prashanth,<br /><br />Not sure if your suggestion makes any measurable difference. However that could be argued, so I decided to modify my script to incorporate your change.<br /><br />Cheers!Rakesh Paihttps://www.blogger.com/profile/00328152982823663876noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-58825031688698162352009-07-16T23:07:57.163+05:302009-07-16T23:07:57.163+05:30I have a suggestion, wont it be better if you have...I have a suggestion, wont it be better if you have assignment and conditional statement above the for loop? well you end up repeating the code but still you need no do assignment or conditional check each time. <br /><br />Example:<br /><br />var sc = "script", tp = "text/javascript";<br />if(window.navigator.userAgent.indexOf("MSIE")!==-1 || window.navigator.userAgent.indexOf("WebKit")!==-1) {<br /> for(var i = 0, l = s.length; i < l; i++){<br /> document.writeln("<" + sc + " type=\"" + tp + "\" src=\"" + s[i] + "\" defer></" + sc + ">");<br /> }<br /> } <br /><br />same on the else as well.prashanthhttps://www.blogger.com/profile/04347017112211551134noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-55053841992163042532009-07-16T22:31:24.185+05:302009-07-16T22:31:24.185+05:30Dude this is awesome!! Thanks for sharing.Dude this is awesome!! Thanks for sharing.Prashanthhttp://prashanthblog.appspot.comnoreply@blogger.comtag:blogger.com,1999:blog-8112154.post-14554004844660154582009-05-04T17:53:00.000+05:302009-05-04T17:53:00.000+05:30Please note, that the new Firefox 3.1 will also su...Please note, that the new Firefox 3.1 will also support defer! You should expand your script with the support of Firefox 3.1. Good article, thanks!adambrunnerhttps://www.blogger.com/profile/00056531358660563607noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-84962406748015612722009-04-29T16:23:00.000+05:302009-04-29T16:23:00.000+05:30Thanks, Aaron.
Callbacks are a great idea, but I ...Thanks, Aaron.<br /><br />Callbacks are a great idea, but I decided not to use that approach here. Consider the case of JS libraries that you might want to include - say jquery. To add a callback to the jquery library is not a good idea since you are modifying the library itself. This doesn't let you load from the Google Ajax APIs for example. Also, upgrading the library becomes hard to do. Hence I dumped the callback approach.<br /><br />Let me know what you think. If you think otherwise, I might consider adding a callback externally to this script.Rakesh Paihttps://www.blogger.com/profile/00328152982823663876noreply@blogger.comtag:blogger.com,1999:blog-8112154.post-67899288833757194512009-04-29T00:46:00.000+05:302009-04-29T00:46:00.000+05:30Hi Rakesh,
nice script, well done!
I tested it o...Hi Rakesh,<br /><br />nice script, well done!<br /><br />I tested it on IE7 and FF3.0.9 on Windows Vista. The scripts load in parallel, order is preserved, scripts on 2 domains. The busy indicator at the mouse pointer in FF *does not* shows until all scripts are loaded. In IE7, the busy indicator does not appear.<br /><br />Imo, not a big issue.<br /><br />Just wondering, would adding a callback for each script be difficult?<br />Would make your script awesome.<br /><br />- AaronAaronhttps://www.blogger.com/profile/02944467793781623269noreply@blogger.com