Drupal and HTTP requests - how low can you go?

UPDATE:
New theme, new code. Click here to read about the way I use cache, and limit HTTP requests now.

Disclaimer: This is an experiment, and would probably not apply to most websites (if any). My mission: Load my homepage in 1 HTTP request without compromising layout or functionality. Just to be clear, the motivation is not to gain any performance from this, just to see if I can do it.

So, back to the point. Drupal has a lot of css, js and image files by default. To load them all you have to ask the server to serve them to you, simple as that. So if you have to ask less times, the page would load faster. In theory. This blog has over 40 requests on the front-page, out of the box. Luckily, Drupal has a number of tools you can use to minimize requests, and among them is the optimization you can find in core. You can find it under the “performance” settings (depending on what version you are on, this is located under “configuration->development” or “site configuration”). Cool. But this still leaves me at more than 10 HTTP requests. I want less! So what next.

So the next step was to avoid loading too many images, so I decided to start with base64 encoding my burning logo (which actually consists of one file pr. letter).

To base64 encode files is extremely simple. What I usually do is use a small php file containing only this:

<?php
$file = file_get_contents('some.file'); //this is the file.
print base64_encode($file);
?>

If you open this up in a browser, you get a long string back. This is your image. To use this in a page, you just go like this:

<img src="data:image/gif;ALONGSTRINGBASE64”>

Obviously, change the “gif” part to whatever you need.

OK, so what else can I optimize. Ah, of course I can do the same with all css rules containing images. Fire up my base64 script again, and the css rule looks for example like this:

#someid {
  background-image: url('data:image/png;base64,A_LOOOOOOONG_STRING’);
}

Simple! Things are getting somewhere.

The next step was to embed the fonts I use, without querying google fonts (hope they don’t read this, as I am not sure if I am allowed to embed them like this, does anyone know?). Same step here with the base64 encoding, and the styles went in to the head tag something like this:

@font-face {
  font-family: 'My cool font';
  font-style: normal;
  font-weight: normal;
  src: local(''My cool font ') , url("data:font/opentype;base64,A_LOOOOONG_STRING”) format('woff')
}

Awesome! The number is decreasing, without compromising the layout.

The two next steps is kind of site-specific, but basically what I tried to do, was iterate over the scripts and stylesheets, and print the contents of the files instead of embedding them. So in a template file I put something like this:

print '<style>';
$style = ''
foreach ($css as $c) {
  // Do some checking of some media query stuff. 
  // ...
  // Then store the raw CSS.
  $style .= file_get_contents($c['data']);
}
//do some regex to remove some stuff, and remove whitespace.
print $style . '</style>';

Cool. We have no requests on css! And now to the javascript.

This was tricky. I have a combination of standard, custom and a couple of compatibility scripts on my site. I had to throw out a couple of them, and do some reordering of the scripts, and then iterate and print them out in a similar matter as the stylesheets.

Since you probably are looking at this page in a full node view (or you would not be able to read this), you may have looked in the inspector and seen that I have well over 30 HTTP requests. Ugh, those external services, eh? The main reason for this is actually the addthis stuff I have at the bottom. So I have over 30 requests extra just to look modern. BUT: If you navigate to the front page I have tossed out all sharing options and actually clock in at an awesome 4 requests. Two of them is google analytics. The other one is there for one and only reason: I use the boost module to serve static pages, so if I want to display that talking burning bird without using cached data, I just have to burden you with a lookup to search.twitter.com. I am sorry to burden you, visitor!

Mission is as much as it can be complete, and I am down to 1 internal HTTP request. Let’s celebrate with an animated gif, folks!

Comments

Great experiment. Have you done any profiling to see what the difference in load times is? You'd want to measure initial load time (cold cache), and subsequent load times. One of the advantages of putting the images, js, css in separate files is browser caching. Presumably, a 2nd load of your page (with a full browser cache) would be faster with the external resources, and your inline technique would be slower. But one only really knows these things after extensive profiling. Clearly, if you can identify a resource that is never being served from cache, and you can inline it, that is a performance win.

-Robert

In addition to what Robert Douglass said a few things to consider....

  • Run both versions of your site on a local box and use a tool like charles proxy to simulate an internet connection. This is important as Internet connections can be inconsistent. This would also let you look at the difference between speeds on a cable modem and mobile (like 3g).
  • Look at the use case across multiple pages. If you include more inline your pageloads will be bigger and you don't leverage caching. Viewing one page may see a performance improvement while multiple pages may take a hit.
  • Compare it to a good caching strategy for static assets (like CSS/JS). That means CSS/JS shouldn't even deal with http requests to see if the file has updated recently.

Awesome! I'm not sure what I like more, the technique or the animated gifs! :P

Nice experiment. Of course the downside to this is the big increase in the size of your HTML file and loss of caching things like images. That impact ca n be far more severe than the extra HTTP requests.

Thanks for commenting. It seems I should have been more clear on my intentions for doing this.
@Jamie:
You are absolutely right. And I am pretty sure I did not gain anything from this experiment. Just a typical case of: "Why did you do that?" - "Because I could"! :)
@robertDouglass:
As I said, this was not an act of reducing load time, just for fun, to see if it was even doable. That being said, some testing would be interesting. Although I have more faith in a combination, than just reducing the number of requests to 1.
EDIT: The results are in!

hi

extremely cool

from a couple of test I have done with this site, it seems that waiting for the content is around 300ms and getting the data 200 ms. Half a second isnt really fast, but if it would be behind a Varnish farm, the one page with all elements could end up being served in around 240 ms. You do have some 50 external elements also however. it actually does partly the same as google mod pagespeed for apache does (http://code.google.com/speed/page-speed/docs/module.html)

But yes, very cool. And something to keep experimenting with!

Thanks for your share, it is very cool.
But I wonder to know if we use CDN, and css sprite to load image. In my opinion, I think CDN+CSS Sprite is a bit fast.
Anyway, thanks for your idea.

I've heard that decreasing HTTP requests is great for serving webpages over mobile networks, the idea being that while bandwidth is limited, the real killer is latency on each request.

I tried loading your homepage from my phone where reception was not great, and while the number of requests may have been low, it actually diminished the experience because page rendering had to wait until the whole page was loaded.

Very interesting experiment, though.

how can i show these tags , which is currently appears in your site...

in my page only one tag is showing which is seleceted by a user

I am not sure what you mean by the question, but if you are looking for the style tag that I am referring to, this article is a little outdated (as stated in the intro). Click that link to read the newest story.

Hope that answers your question.