Most of us (me included) don’t think much about the way DNS works. Browsers, on the other hand, use DNS pretty much every day. For the uninformed, I will start by explaining how DNS works. If you already know this, feel free to skip the following paragraph.

As you know, all computers with a network card installed are awarded an IP address, which is four (or more) numbers separated by dots. When you do a request on a webserver, you are actually making an HTTP request to an IP address. Inputting IP addresses in the browser would make browsing the web just plain horrible. The DNS was invented to avoid having to remember IP addresses. When requesting a domain name, like www.hippovalidator.com, your browser asks the DNS to resolve the inputted domain name to an IP address. The request is then sent to the IP address returned by the DNS server, making it easy and painless for you to request a webpage.

Now then, why do we as performance-optimizing wizards need to worry about DNS? Well, in my opinion, we don’t. According to the YSlow documentation, a single DNS request typically takes 20-120 milliseconds. This may not seem much, but imagine the following HTML header example code:

 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
 <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js"></script>
 <script type="text/javascript" src="http://static.myrating.dk/rating.js"></script>
 <script type="text/javascript" src="http://connect.facebook.net/en_US/all.js"></script>

<script src="http://cdn.uservoice.com/javascripts/widgets/tab.js"></script>

The browser needs to make 5 requests to the DNS server in order to fetch the referenced scripts. Worst case scenario, this will (according to YSlow) take as much as 600 milliseconds. This is a substantial amount of time! How do you avoid this?

Option 1: Reference less stuff from other domains.

Option 2: Copy the referenced stuff from the other domains to your own domain (in the example above, the scripts could all reside on the local domain).

So let’s head back to my point about DNS not being important. In fact, I don’t think you should implement any of the solutions mentioned above. Why?

1. Because of DNS caching. When your browser asks a DNS server for an IP address, the result is cached in the browser’s local DNS cache. Chances are, your ISP already has the result cached as well.

2. Because of prefetching in all modern browsers. Every single browser that I can think of does some sort of prefetching. In Chrome, a background thread parses all domain names in a requested HTML document and resolves the domain names while you look at the page. IE does something similar.

3. Because reducing DNS lookups also reduces the number of simultaneous downloads in the browser. As I mentioned in a previous post, the browser is not able to make unlimited simultaneous requests to the same domain. That’s why my recommendation is to use jQuery (and similar from Google’s or Microsoft’s CDN) and place all of your static files like images, scripts, and style sheets on a subdomain. This would result in more DNS lookups, but it would optimize the browser’s possibilities to fetch the needed resources.

The conclusion is this… Don’t be alarmed when YSlow warns you about reducing DNS lookups!

We’ve briefly touched this subject a number of times already. Making your JavaScript and CSS external simply means moving it from your HTML header to their own files, referenced as an external file in the header. So why does Yahoo think that this is a good idea? We’ve already discussed the possibility to cache resources in the browser client-side cache. Caching scripts and styles is definitely easier than caching HTML. JavaScript and CSS are typically only changed when changing something on the site like new styling, new features, etc. Changing HTML happens all the time when users write new content, new search results are found, etc. When inlined, the scripts and styles are typically not cached or at least not for a very long time. But wait, here’s the real bonus: scripts and styles are typically shared between multiple views. Moving all that static stuff to external files will make the browser cache them, serving the cached versions when loading page number 2, 3, and so on.

The YSlow documentation argues that you can sometimes benefit from inlining your script and styles directly in the HTML. This only goes for pages with a single page view per session like the Yahoo front page. I can see the point and noticed that pretty much all search engines do this. I still think that you should get a lot of visitors in order to do this kind of thing. So unless you’re Google or your front page uses an entirely different styling than the rest of your site, you should be covered by moving the static stuff to external files.

Another benefit is when debugging through Firebug. When I need to debug some inlined JavaScript, I typically spend some time wondering and then realizing that I can’t debug JavaScript from the HTML tab in Firebug. This usually causes a bit of confusion and sometimes even some pulling out of precious hair strands. The solution is to navigate to the scripts tab and selecting the HTML file. I can understand why the UI works that way, but I keep forgetting. Moving all JavaScript to an external file forces me to navigate to the scripts tab right away.

(Proofread by inWrite)

We have reached rule number 4 in our journey into the exciting world of the YSlow rule set. Rule number 4 is all about caching. We have tackled the caching area a bit in some of the previous posts, but in this post I will dig more into this important area.

Showing webpages is all about getting resources like HTML, JavaScript, and images from the server and combining them in a showable way in the browser. I’ve previously talked about how to minimize the number of requests to the server, but what do we do when we have removed all the unnecessary requests with SquishIt and similar tools? One of the answers is caching, which is applicable for pretty much all pieces of a webpage. I will not explain any basics about HTTP caching. If you are not familiar with the subject, you should check out Mark Nottingham’s great Caching Tutorial.

So what’s the buzz about the Expires and Cache-Control headers? Both terms are part of the response header, which is used to tell clients if the response can be cached. Rather than explaining you all the theories, I would rather show you how I’ve implemented caching in one of my Danish ASP.NET MVC-based websites named myrating.

The problem

On my “product” pages I show similar items in a column to the right of the product info. Similar content is pretty performance heavy to calculate because of the algorithm, which is based on tags, ratings, and even more stuff. As a result, loading the product page was very slow, caused by the small similar items box.

The solution

I decided to do two things. The first solution was to wait for the rest of the page to show and load the info box async. I will show you how to do this in an upcoming post, but right now we will focus on the second solution: caching the response. I could have implemented the caching in an HTTP module but decided to implement a new action filter for ASP.NET MVC. This way I can annotate all the methods in my ASP.NET MVC project, the result of which can be cached. The action filter looks like this:


public class CacheableAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        filterContext.HttpContext.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
        filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.Public);
        filterContext.HttpContext.Response.Cache.SetValidUntilExpires(true);
    }
}

In line 5 I set the Expires header to a week from now. I’ve hardcoded this time span but could as well have implemented a property for making this configurable.

In line 6 I set the cacheability to public. This basically means that all parties can cache this, including both browsers and proxies.

In line 7 I set valid until expires to true to avoid cache invalidation sent from the browser. This way I control how long the response is cached, and not the browser.

Making responses cacheable for one week is now piece of cake. All I need to do is to add the Cacheable attribute to the action methods which can be cached like this:


[Cacheable]
public ActionResult FindSimilarItems(Guid id)
{
    ...
}

(Proofread by inWrite)