Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Improving Javascript Load Times - Concatenation vs Many + Cache

I'm wondering which of the following is going to result in better performance for a page which loads a large amount of javascript (jQuery + jQuery UI + various other javascript files). I have gone through most of the YSlow and Google Page Speed stuff, but am left wondering about a particular detail.

A key thing for me here is that the site I'm working on is not on the public net; it's a business to business platform where almost all users are repeat visitors (and therefore with caches of the data, which is something that YSlow assumes will not be the case for a large number of visitors).

First up, the standard approach recommended by tools such as YSlow is to concatenate it, compress it, and serve it up in a single file loaded at the end of your page. This approach sounds reasonably effective, but I think that a key part of the reasoning here is to improve performance for users without cached data.

The system I currently have is something like this

  • All javascript files are compressed and loaded at the bottom of the page
  • All javascript files have far future cache expiration dates, so will remain (for most users) in the cache for a long time
  • Pages only load the javascript files that they require, rather than loading one monolithic file, most of which will not be required

Now, my understanding is that, if the cache expiration date for a javascript file has not been reached, then the cached version is used immediately; there is no HTTP request sent at to the server at all. If this is correct, I would assume that having multiple tags is not causing any performance penalty, as I'm still not having any additional requests on most pages (recalling from above that almost all users have populated caches).

In addition to this, not loading the JS means that the browser doesn't have to interpret or execute all this additional code which it isn't going to need; as a B2B application, most of our users are unfortunately stuck with IE6 and its painfully slow JS engine.

Another benefit is that, when code changes, only the affected files need to be fetched again, rather than the whole set (granted, it would only need to be fetched once, so this is not so much of a benefit).

I'm also looking at using LabJS to allow for parallel loading of the JS when it's not cached.

Specific questions

  • If there are many tags, but all files are being loaded from the local cache, and less javascript is being loaded overall, is this going to be faster than one tag which is also being loaded from the cache, but contains all the javascript needed anywhere on the site, rather than an appropriate subset?
  • Are there any other reasons to prefer one over the other?
  • Does similar thinking apply to CSS? (I'm currently using a much more monolithic approach to CSS)
like image 200
El Yobo Avatar asked Apr 25 '10 07:04

El Yobo


People also ask

Where should I place a script for best page load speed?

1. Place the script Tag at the Bottom of the Page. When you place the script tag at the bottom of the page after the main content, there will be some performance improvement. The content of the page will load and get parsed, as there is no blocking behavior for rendering HTML since you have placed the script in the end ...

How can I make jquery load faster?

Try moving your js file at bottom of page just before closing body tag, this way script will not halt loading of page resources such as CSS.


3 Answers

2021 Edit:
As this answer has had some recent upvotes, do notice that with http 2.0 things changed a lot. You don't get the per-request hit as you now multiplex over a single TCP connection. You also get server-push. While most of the answer is still valid, do take it as how things were previously done.


I would say that the most important thing to focus on is the perception of speed.

First thing to take into consideration, there is no win-win formula out there but a threshold where a javascript file grows into such a size that it could (and should) be split.

GWT uses this and they call it DFN (Dead-for-now) code. There isn't much magic here. You just have to manually define when you'll need a need a new piece of code and, should the user need it, just call that file.

How, when, where will you need it?
Benchmark. Chrome has a great benchmarking tool. Use it extensivelly. See if having just a small javascript file will greatly improve the loading of that particular page. If it does by all means do start DFNing your code.

Apart from that it's all about the perception.

Don't let the content jump!
If your page has images, set up their widths and heights up front. As the page will load with the elements positioned right where they are supposed to be, there will be no content fitting and adjusting the user's perception of speed will increase.

Defer javascript!
All major libraries can wait for page load before executing javascript. Use it. jQuery's goes like this $(document).ready(function(){ ... }). It doesn't wait for parsing the code but makes the parsed code fire exactly when it should. After page load, before image load.

Important things to take into consideration:

  1. Make sure js files are cached by the client (all the others stand short compared to this one)
  2. Compile your code with Closure Compiler
  3. Deflate your code; it's faster than Gziping it (on both ends)

Apache example of caching:

// Set up caching on media files for 1 month <FilesMatch "\.(gif|jpg|jpeg|png|swf|js|css)$">     ExpiresDefault A2629744     Header append Cache-Control "public, proxy-revalidate"     Header append Vary "Accept-Encoding: *" </FilesMatch> 

Apache example of deflating:

// compresses all files for faster transfer LoadModule deflate_module modules/mod_deflate.so AddOutputFilterByType DEFLATE text/html text/plain text/xml font/opentype font/truetype font/woff <FilesMatch "\.(js|css|html|htm|php|xml)$">    SetOutputFilter DEFLATE </FilesMatch> 

And last, and probably least, serve your Javascript from a cookie-less domain.

And to keep your question in focus, remember that when you have DFN code, you'll have several smaller javascript files that, precisely for being split, won't have the level of compression Closure can give you with a single one. The sum of the parts isn't equal to the whole in this scenario.

Hope it helps!

like image 78
Frankie Avatar answered Oct 14 '22 00:10

Frankie


I really think you need to do some measurement to figure out if one solution is better than the other. You can use JavaScript and log data to get a clear idea of what your users are seeing.

First, analyze your logs to see if your cache rate is really as good as you would expect for your userbase. For example, if each html page includes jquery.js, look over the logs for a day--how many requests were there for html pages? How many for jquery.js? If the cache rate is good, you should see far fewer requests for jquery.js than for html pages. You probably want to do this for a day right after an update, and also a day a few weeks after an update, to see how that affects the cache rate.

Next, add some simple measurements to your page in JavaScript. You said the script tags are at the bottom, so I assume it looks something like this?

<html> <!-- all your HTML content... --> <script src="jquery.js"></script> <script src="jquery-ui.js"></script> <script src="mycode.js"></script> 

In that case, you time how long it takes to load the JS, and ping the server like this:

<html> <!-- all your HTML content... -->  <script>var startTime = new Date().getTime();</script>  <script src="jquery.js"></script> <script src="jquery-ui.js"></script> <script src="mycode.js"></script>  <script> var endTime = new Date().getTime(); var totalTime = endTime - startTime; // In milliseconds new Image().src = "/time_tracker?script_load=" + totalTime; </script> 

Then you can look through the logs for /time_tracker (or whatever you want to call it) and see how long it's taking people to load the scripts.

If your cache rate isn't good, and/or you're dissatisfied with how long it takes to load the scripts, then try moving all the scripts to a concatenated/minified file on one of your pages, and measure how long that takes to load in the same way. If the results look promising, do the rest of the site.

like image 32
Annie Avatar answered Oct 14 '22 00:10

Annie


I would definitely go with the non-monolithic approach. Not only in your case, but in general gives you more flexibility when you need something changed or re-configured.

If you make a change to one of these files then you will have to merge-compress and deliver. If you are doing this in an automated way then you are OK.

As far as the browser question "if the cache expiration date for a javascript file has not been reached, then the cached version is used immediately; there is no HTTP request sent at to the server at all", i think that there is an HTTP request made but the with response "NOT MODIFIED". To be sure you should check all the Requests made to the Web Server (using one of the tools available). After the response is given then the browser uses the unmodified resource - the js file or image or other.

Good luck with your B2B.

like image 32
Andreas Avatar answered Oct 14 '22 02:10

Andreas