views:

94

answers:

4

I'm interested in hearing opinions on how to efficiently organise JavaScript (and jQuery) in a largish web application project that could potentially see high traffic.

Things that concern me are:

  • Being efficient on the server
  • Being efficient on the browser
  • Keeping the codebase manageable

Lets assume that all authored JavaScript is kept in one massive application.js file which in turn is concatenated together with all external libraries into one single js file that the server has to deliver. This should be most efficient on the server as it only has to serve it up once and then the browser will cache it for each subsequent page load.

Contained within it are lots of custom jQuery functions hooked to selectors like this:

$('#my_unique_selector').bellsAndWhistlesPlugin();

Where the above selector is only present on a few pages, using the methods of serving everything in one bundle means that every page load the browser has to both parse the plugin code (that isn't going to be used), and then interpret the bellsAndWhistlesPlugin() method, even though the selector doesn't find a match.

So I guess my question is, at what point does this approach become inefficient? Is there and argument for splitting up the JavaScript and only serving up the bits that are required for each page? Or am I worrying about nothing - browsers are more than capable of dealing with loads of redundant code?

A: 

My personal approach is to use hosted code (I use googles jquery repo) and to put all my global assets (javascript files, css, images used by css) in a gzip file.

ToonMariner
You mean you serve your js and css gzipped, they cant all go in one file!
redsquare
A: 

if $('#my_unique_selector') does not find any matches the method being called on it will happen zero times. You are still running the '#my_unique_selector' query but bellsAndWhistlesPlugin() will never be called.

Nick
Is that correct though? I thought the `bellsAndWhistlesPlugin()` gets called but no jQuery object gets passed to it? (I've had poorly written plugins cause all my JavaScript to crash for this very reason). On it's own it may not be a big deal, but if this happens 60+ times surely there's a point where an older browser might start to complain?
aaronrussell
A: 

Was looking to post something really similar to your question the other day until I stumbled on this:

http://stackoverflow.com/questions/386885/is-there-a-javascript-mvc-micro-framework While I did look at javascriptMVC's doc a little I did not had time to fully go trough it. It sounds like it's going to require a major rewriting to get it started..

I guess you are however in the right way trying to tackle these issues as early as you can in your project.

matdumsa
+1  A: 

Something you should definitely NOT do is concatenate all your JavaScript into a single file. If you ever make a change to your codebase, that file is recreated... and redistributed to every visitor. HTTP overhead is fairly insignificant, so unless you are loading hundreds upon thousands of unique files, loading 20 different files versus loading 1 big one won't show much of a difference except to users with exceptionally slow connections (who will be waiting for the big file anyway, so they won't notice an extra second or two from the HTTP overhead).

ToonMariner's suggestion to use hosted code (particularly off the Google Code repos) is a good one - it saves you having to host the file, it allows users who have encountered that file to take advantage of caching (improving the apparent load speed of your site), and it won't get included in your concatenated file if you make a change. Even if you choose to maintain your whole app in one big file, you should look into using this, since you can avoid packaging jQuery and that's a savings of 50+kb.

Furthermore, your concern about interpreting bellsAndWhistlesPlugin() is correct - the this in the bellsAndWhistlesPlugin function is simply an empty list (though I should hope the plugin does a $(this).each call to iterate over elements and returns early, since there are no elements... otherwise, you may want to revisit your plugins!). You can eliminate this problem by removing page-specific code from your full application.js file and putting it in an inline <script> element on the page itself, where it belongs anyway, or rewriting the plugin to make it return early if there are no matching elements.

Just make sure you enable caching for resources loaded from a /js directory and you won't have issues with reloading libraries - only ones that have changed. You can use an Expires header or a Last-modified header; Expires won't necessarily force an update unless the person reloads or the cache has expired, and Last-modified invokes an HTTP overhead for each file, which is problematic for a larger number of files. You'll have to evaluate the tradeoffs for your application.

If you are really, truly, seriously interested in maximum efficiency, you can rewrite your application using GWT. That technically guarantees maximum cross-browser portability, maximum code efficiency, eliminates dependency on jQuery libraries, will execute faster, and produces much smaller filesizes. All in one file, I might add, but the tradeoffs for getting a static compiler to put out maximum efficiency JavaScript are worth it... if you are willing to rewrite the whole thing in GWT.

The question you have to ask yourself is: who is my average user? What kind of connection does s/he have? Does my app need to run on mobile devices? If your average user has a fast connection, don't worry about it - they'll load your page fast enough whichever way you choose. If you need to work on mobile devices, or your intended audience has a slow connection speed, consider caching your large libraries that change very infrequently and using external repos where available (e.g. jQuery), then package the rest of your app into one big file. HTTP overhead for mobile devices and slow internet is significant enough to warrant doing this.

Scott R
Scott, that's an excellent answer and one well worth waiting the +1 months since I asked this question for, thank you :)Your point about placing page specific code such as `$('#my_unique_selector').bellsAndWhistlesPlugin();` in inline `script` tags in the page is an interesting one. In the project that spurred me to ask this question I've made a concerted effort to keep all that kind of code in one central place from a maintainability point of view - rather than having disparate lines of JS dotted all over the place. I guess I might have been being a tad over zealous on reflection :)
aaronrussell
In retrospect, as long as your plugin is doing a $(els).each call to iterate over each element, you won't invoke any overhead for the actual function call; as for packaging it up and worrying about that overhead, it's already cached, no big deal. If multiple pages have the #my_unique_selector, or you might create pages in the future that have it, leave it in your common files; if it is unique per page and will never be replicated, it definitely belongs in an inline <script> tag, just as coding best practices :)
Scott R