Javascript | Performance

Combine Your JavaScript Files. Now.


March 19, 2008 07:55 by joel

Don't argue, just do it. Then read this post to find out why (Hopefully lots of you will already understand why. That's fine. I won't be insulted if you skip this post.).

This topic came up in one of the presentations at Toronto Code Camp this year. Richard Campbell (.NET Rocks) is a great speaker. Not only is he knowledgable, but he's engaging, as well. He's one of those speakers that makes you feel like you'd still be enjoying his presentation, even if you had accidentally stepped into the wrong seminar and had no idea what he was talking about.

The presentation in question was on the topic of "The Scaling Habits of ASP.NET Applications". He provided a ton of useful information, but for the purpose of this post I'm only going to cover one point, which jumped out at me since I spend most of my time on the client-side of things. To be honest, it was the reaction to his comment that jumped out at me the most. The quizzical looks on a lot of the audience, and the number and variety of questions made me realize that a lot of people working in this industry aren't aware of some of the more basic mechanics of browsers and the internet itself. I'm not criticizing, as it is easy to overlook certain things (I'm confident that I make some dumb mistakes, or overlook obvious things pretty often). It just surprised me.

Before you read any farther, download YSlow. You can no longer claim ignorance if questioned. You need this tool (along with Firebug, but you've already got that, right?!?).

Click on the logo in the information bar, and YSlow will analyze the current page, giving a grade from A to F in a variety of performance areas. Expanding an area will give you a bit more detail on the offending files/components and clicking on any of the headings will open a description of what the particular heading refers to. The first area you are marked on, and the one that this post is concerned with, is "Make fewer HTTP requests". Here is Yahoo's description of the best practices for this area. It makes reference to image maps, CSS Sprites, and combining your JavaScript files. Is it really that important, though? What's the difference between one 200k js file and two 100k files?

The root of this problem lies in the fact that the browser can only handle two requests at the same time (this is adjustable from about:config in firefox, and perhaps also in IE, but it won't do you any good, as the limitation is there for a reason and large explosions WILL occur if you tamper with that value). This causes problems because every time you make a request for a particular file (image, css, js, whatever), there is an inherent "round-trip time" (RTT) which is tacked on to the load time of your page. You can't put servers next-door to every one of your users, so a basic analysis using highschool physics reveals the fact that talking to the server takes time. The value of the RTT is out of your hands (unless we start talking about distributed servers and CDN's, but that's way outside the scope of this post, and the budget of most small to medium-sized projects). It's a constant which you need to take into consideration when developing each and every page in your application.

(I debated whether or not to include an equation in this post. I'm not going to, but If you would like to dig deeper into these performance issues, there is a report which Richard made reference to that goes into much greater detail. Although you can just search for it directly, I don't think I'm supposed to link directly to the report. So if you'd like to register first, for their benefit, head here. The report is centered on issues facing Application Delivery Systems. At the outset, however, there is some excellent information on the performance issues facing any developer. The equation on the third page of the report is of particular relevance.)

Often, when trying to optimize the performance of an application, a developer will spend countless hours on the code itself. As client-side programming has become more prevalent, a lot of attention has been focused on the size of JavaScript files. While it's important not to have superfluous code, spending countless hours refining your code is rarely time well spent. If the application does what it is supposed to, optimize other areas first, then as a last resort you can spend some time tweaking the code.

To illustrate what I am saying, let's consider a small example. Assume that the total size of all files associated with a certain page is 350.5K. Internet connections are getting faster, generally, so I'll just use my connection as an example. According to speedtest.net, my download speed is 6846kb/s. This means that bandwidth accounts for approximately 51ms of the total page load time in this example. Yet the page took 3.627s to load (initial load, no caching). There are a lot of other factors affecting the load time, all of which are included in the equation which I mentioned previously. RTT, however, is the one that this post is concerned with, so let's see how it affects the total time it takes our page to load. When I ping the server, I get an RTT of 102ms. So, with a total of 27 HTTP requests, at 102ms each, taking into account that we can do 2 at a time, we get a total of 1.377s. This means that 38% of our load time is attributable directly and exclusively to the length of time it takes something to get from the client to the server and back again.

Let's go back for a second to the ways that most developers initially try to optimize their page-load time. Optimizing your script files is going to make a bit of a difference. But there's only so much you can do there. You might spend two days optimizing your code and find that you can cut a few Kb off the filesize and 30 to 40 milliseconds off the time it takes the browser to parse the page. If you've done a good job writing your code, that much of a savings might not even be realistic. We'll use it as an example anyway. You've just spent two days and managed to pull off a 1% savings on initial load time. "Not too bad" you say as you pat yourself on the back.

Now let's pretend that you left your computer on and your 10 year-old, just learning the intricacies of notepad and figuring he'd give you a hand, cut and pasted all of your 8 JavaScript files into the same file. When you discover what has happened, you panic, but decide to load the page anyway, just to see what happens. To your surprise, the page still works, and it loads in 3.27s. This means that in 15 action-packed minutes, your 10 year-old managed to cut 357ms from the load time: somewhere in the vicinity of 10 times better than you were able to do in two days of work.

That was obviously a very simplified example. If you check out the resource that I mentioned (mainly the various components of the equation), you'll realize that there are many more factors involved in the time it takes to load the page. The load times I mentioned, and the savings I mentioned, however, are very real. You won't have to look very far to find web pages that pull in eight or more JavaScript files. Cutting their size, using a utility such as Yahoo Compressor, and gzipping them are all important optimizations that you should be doing already. When you combine that with a reduction in the number of requests you are making you will have achieved the biggest performance boost that your page can get, without adjusting a single line of code. When you begin to dig deeper than that, the solutions will continue to get more difficult, more expensive, and will provide you with smaller performance enhancements.

What I hope you take away from this post: Do the cheap and easy optimizations first, and the expensive and time consuming options may not even be necessary.



Related posts

Comments

March 19. 2008 14:44

This is a spectacular post, Joel! Haven't thought about stuff like for probably five years. You make very strong points, it was easy reading, too.

I keep my Javascript and stylesheets separated to reduce the overall file size, and keep relevant stuff together. For instance, I don't need any "comments" logic on my "about me" page. Not just that, but I like to keep things separated for organizational purposes. This post opened my eyes and made me realize that keeping things separated comes with a pricetag.

I can't help but feel there is a way to get the best of both worlds. We can keep things separated, and still make a single request to get what we need. How about an HTTP handler to accept query strings specifying which javascript files you need (all the actual Javascript would remain separated, and stored in Cache in Application_Start) and spit them out in the response. Something like

<script type="text/javascript" src="javascript.ashx?files=common,blogPosts,comments"></script>

Then the handler would interpret the query strings, gather the relevant Javascript, set the response type correctly, and stream it out in the response.

I wonder if this would indeed be the best compromise. I'd hate to lose separation; the maintainability benefits are unsurmountable. But I also hate the performance blow. I might have to do some testing with this.

Thanks again for the great post that got me a-thinking!

Josh Stodola

March 25. 2008 13:07

Hey Josh,
Thanks for the comment. I totally agree with your thoughts on maintainability and separation. I definitely wasn't trying to say that building one physical JavaScript file is the only answer. Merely trying to find an attention grabbing way of pointing out the performance issue Smile
I spent a bit of time today looking into this and stumbled across this post on Code Project: www.codeproject.com/KB/aspnet/httpcompression.aspx
I was going to try and write something on my own, and I'm still going to dig into it a bit, but it'll be interesting to see how his performs. Rather than putting a reference directly to the handler, his implementation actually parses the page, combining all of the CSS and js references, and compressing them.

joel

Add comment


 

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

July 23. 2008 18:21