다음을 통해 공유


Speed up your website!!

If you search for keywords like website speed, performance, improvement you will get lot of articles describing lot of ways to do this.

The question is how easy is to implement all of them in my project. Do I have time, resources for this? My project is already running from last few or more years and now how to incorporate all these in my project?

Believe me I tried all these ways on project which was running from more than 4 years. You have code written by many developers, you don’t have an architect who can control the way project is developed. Every individual has its own way of development. And in large project it’s not easy to manage and control the way each line is written. After few years you will find everything is a mess, even a code written by you. Is this what I have written few years back? And then changing the code to improve the speed seems daunting.

What we are going to talk today is about HTTP Combiner and its implementation in ASP.NET. Non .NET developers can still read this article as it talks more about concept rather that actual code.

Now before we deep dive into the topic lets understand what happens when web page loads. To do this you will need tool like HTTP Watch (Basic edition is free and can be found here). There are some other tools available like fiddler etc.

The screen shot bellow is first page load of Microsoft.com
 

 

If you look at it takes around 9 sec to completely load the page which includes download of 370 KB of data. Now it depends on your network as well but the next time I press F5 the time to download is reduced to around 6 sec and further if hit Enter (remember there is difference between page refresh by saying F5 and Enter) the time it took was around 4 sec.
Interesting to see what happens there? For that let’s first understand some basic HTTP status codes.

200 
OK 

Standard response for successful HTTP requests.

304 
Not Modified 
Indicates the resource has not been modified since last requested. Typically, the HTTP client provides a header like the If-Modified-Since header to provide a time against which to compare. Using this saves bandwidth and reprocessing on both the server and client, as only the header data must be sent and received.

404 
Not Found 
The requested resource could not be found but may be available again in the future. Subsequent requests by the client are permissible

 

You can get all of them explained in detail here.

If you refresh the page second and third time as explained above with example of Microsoft.com, and carefully observer the status code you will see lots of JavaScript files, CSS and images whose status code were 200 in first request are not converted into 304. For some of them you won’t see any status code instead something like (cache); which indicates that no HTTP request was sent to the server; the object was present in browser cache.

To improve the performance of web page the best method is reduced number of request sent to and received from the server. You will see that simple web page has lots of request and most of them are images, CSS and JavaScript or other resource file. And best way is to cache them at client. But trick here is that you need to judge that what can be cached and what cannot be; simple rule is to determine what is static and dynamic on your website.

My personal experience is, once your site is deployed to live environment; none of the JavaScript file, CSS file or image file changes unless you do next version upgrade or deployment on live server which should not be less than 2 months in any case.

What we are going to do with HTTP combiner is to combine all of them and send to the client in one request with some caching information in header so that browser can keep them until we change it.

To take maximum advantage of this technique you need to ensure that you move all your JS which is on ASPX/ASCX pages or rendered directly from the server code to the separate JavaScript files. And as good technical manager I would favour writing many small JavaScript and CSS files instead of one large JavaScript/CSS file for better code maintainability, and in fact it is a good practice.

Now before I go and show the code to you, let’s think of this scenario theoretically. Every HTTP request results in a network round trip form your browser to the server and the delay in reaching the server and coming back to the browser is called latency. You have a page with 4 JavaScripts and 3 CSS files; you are wasting time in seven network round trips. Within USA, latency is average 70ms. So, you waste 7×70 = 490ms, about half a second of delay. Outside USA, average latency is around 200ms. So, that means 1400ms of waiting. Browser cannot show the page properly until CSS and JavaScripts are fully loaded. So, the more latency you have, the slower page loads. And then you 10 images on page which will be loaded step by step.

Here’s a diagram that shows how each request’s latency adds up and introduces significant delay in page loading:

 

 

When next time visits the site same thing happens again and again. Now whatever is displayed on web page is actually first downloaded to a temporary folder by browser and then displayed on web page. When I visit the web page next time same thing happens again and again, why? Browser knows which CSS to load and which image to display then why can it display image or load CSS which is already there in local cache? Well, browser can do that but you need tell it, computer/software is a lazy thing which requires command from user do to each and every thing and your browser is not exception to that in certain cases.
What we can do? Let’s divide it into three parts.
1. Ask browser to cache each file (JavaScript, CSS or image)
2. Combine all JavaScript or CSS in one single request. Use part one for this single request as well.
3. Combine all possible groups of images into single request. Something called as CSS sprites.

1. Asking browser to cache files

HTTP Request:

GET /Default.aspx HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-IN,en-US;q=0.5
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
Accept-Encoding: gzip, deflate
Host: localhost:16010
DNT: 1
Connection: Keep-Alive
Pragma: no-cache

The structures of any 200 HTTP response will something like bellow.
 
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Last-Modified: Fri, 19 Jul 2013 02:53:47 GMT
Vary: Accept-Encoding
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcc3VwYXRpbFxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEyXFdlYlNpdGVzXFdlYlNpdGU4XERlZmF1bHQuYXNweA==?=
X-Powered-By: ASP.NET
Date: Fri, 19 Jul 2013 02:53:47 GMT
Content-Length: 721

Header filed definitions are mentioned here at https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

What we are interested in is LastModified date. First time you are sending some content to the browser you must add

context.Response.Cache.SetLastModified(<date time>)

along with your content. Now when user refreshes the page in browser you receive the second request for that on server. This time you should inspect the request header by using code 

context.Request.Headers["If-Modified-Since"].

Here you get the date of file which is on client. Now you can compare that with actual file you have on server. You find that server and client have same file. Now tell the browser that if you have it I won’t send it to you. Here browser is intelligent enough not to load modified object from its locale cache. And the code for same would be

context.Response.Clear();
context.Response.StatusCode = 304;
context.Response.StatusDescription = "Not Modified";
return;

 

And you are done. If you inspect the request response of your web pages with HTTP watch/fiddler your find that every file which is not modified is sent as 304 second time onwards.

2. Combine all files in one request to improve

 

Simple answer is to combine all of the JS files or CSS files in one request.
1. Suppose you have 10 JS files
2. What you can do read each file from disk one by one and add them to some memory stream.
3. You will have byte array of all the files together. This will be large in size, of course!
4. You can use some compression algorithms like GZIP to compress it.
5. Now you have stream or byte array of all files in compressed format.
6. Write all them to client in single request.
Yes! You are done. More to that if you combine caching algorithm explained in part1 then this single request will be cached by browser for long time.

I have developed one control called HTTP combiner which does all this work for you. And writing JS and CSS is very simple with this.

  <myControl:ScriptStyleManager id="SSManager1" runat="server" BaseFilePath="Resources\Text\">
        <Stylesheets>
            <myControl:FilePath Value="CSS/StyleSheet1.css" />
            <myControl:FilePath Value="CSS/StyleSheet2.css" />
            <myControl:FilePath Value="CSS/StyleSheet3.css" />
        </Stylesheets>
        <Javascripts>
            <myControl:FilePath Value="JavaScript/JavaScript1.js" />
            <myControl:FilePath Value="JavaScript/JavaScript2.js" />
            <myControl:FilePath Value="JavaScript/JavaScript3.js" />
        </Javascripts>
    </myControl:ScriptStyleManager>

This is a live example; where all the files (3 JS + 3 CSS) are loaded in single request.

3. Combine all possible groups of images into single request

You cannot combine images in by the technique explained above as from storage point of view image is much complex object. The best technique which exists is to make one large image of all small images and use the large image along with CSS positioning in all places where the small images were used.

The technique is call as CSS sprites and used mainly by CSS designers. As this is out of scope of this article from development point of view I won’t explain it in much detail. What you can do is read more about it @ https://CSS-tricks.com/CSS-sprites/ .

This was just a try from my side to share one of the speed improvement s techniques. As said earlier there exists lots more; and you are the best judge of your website/project. If you know some better techniques or have some exposure to different implementation of HTTP combiner then please let me know.

Comments

  • Anonymous
    July 18, 2013
    Hi Subodh, If possible provide code link for your control, it will help us all to simply add it in our project and use it.. Thanks for a good post. regards, Vikas

  • Anonymous
    July 22, 2013
    Hi Vikas, It will take some time to share the complete code. However in weeks time will update the basic code. Thanks, Subodh

  • Anonymous
    March 19, 2015
    Thanks Subodh, this was very helpful, I have a question though. How you are going to update these js and css files once these are updated in code.