Thursday, April 27, 2006

Speed up your AJAX based webapps

UPDATE: I guess most people are not getting what this technique does in the first place. It sets the expiry of the JavaScript to years and not days. Once the JavaScript file is downloaded it is never downloaded again, ofcourse unless you force it by removing the file in the cache. If you visit the site often the JavaScript will not be removed from the cache. If you make any changes to the JavaScript you only need to change the version of the file and the new file will be downloaded. The older file is automatically removed from the cache when it is no longer requested. And just to add one more point this can be done on the WebServer itself without using this technique, but that has its own drawbacks. To further speed up the download you can gzip the JavaScript.


If you have developed an AJAX based web application you would know how many JavaScript files are required per webpage. If you use the prototype or dojo toolkit library you would know how big those JavaScript files can turn out to be.

I am currently developing a website fefoo.com, and I learned a few things about caching and how you can speed up your website for users who visit your site often. A website like digg takes up more than a minute to load on my dialup connection even though the main page is no more than a 27-32 KB. The real time is taken up by the JavaScript files. The solution for this problem is to cache the JavaScript files. Though caching improves the speed but it causes a problem when you have to update the JavaScript files, since the browser will not look for updated files if they have been cached.

Since your files are cached they will not be requested by the browser and you will not be able to send out updated JavaScript files. The solution to this problem is that you use a different name for your JavaScript file every time, or you can version control your directory. So for version 0.1 of your project http://testserver.com/javascript/0.1/test.js, and for 0.2 http://testserver.com/javascript/0.2/test.js

Thought this solution is good but it's still difficult to implement, and soon you will have multiple directories to take care of, and you will face problems when only one file needs to be changed.

After facing the trouble of a slow server and the JavaScript file being downloaded every time, I came up with this solution for PHP and .net based web application. You need to download getjs.php or getjs.aspx depending on your server. To load a script file use
<script src="getjs.php?file=test1&version=0.1" />
<script src="getjs.aspx?file=test2&version=0.2" />

In this example we load two files test1.js and test2.js. This solves two problems firstly it will work even if you have virtual hosting and secondly it solves the problem of multiple files. So if you wish to change only one file change the version from 0.1 to 0.2 and the new file will be downloaded and cached. In the next article I will try to tell you how this has been implemented, though if you know PHP or VB.net and have some idea about HTTP you won't face too many problems.

You can view a demo to see how you can improve your own web applications using prontoCache.
<?php
/*
* Author: Vivek Jishtu
* Copyright (c) 2006 Viamatic Softwares
*/

/**************************************************
This acts like a security measure also. So no
other extension except JavaScript can be downloaded.
**************************************************/

$filename = $_GET["file"]. ".js";
header("Content-Type: text/javascript");
if(!file_exists($filename)) {
echo "alert('The file [" .htmlspecialchars($_GET["file"], ENT_QUOTES). "] does not exist. Please inform webmaster.');";
exit;
}

$if_modified_since = preg_replace('/;.*$/', '', $HTTP_IF_MODIFIED_SINCE);
/**************************************************
The javascript never expires so if we get any
Request for a modified page we send back that
javascript has not been modified.
**************************************************/
if ($if_modified_since != "") {
header("HTTP/1.0 304 Not Modified");
exit;
}

/**************************************************
Set the cache such that it does not expire. In
this example we set it till 22nd Feb 2011.
You can change the date to whatever year you want,
any year in the future.
**************************************************/
header("Last-Modified: " . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header("Expires: Tue, 22 Feb 2011 05:00:00 GMT");
header("Cache-Control: public");

echo "/* prontoCached on ". gmdate('D, d M Y H:i:s', time()) . " */\r\n";
require_once($filename);
?>
The PHP Code
<%@ Page Language="VB" %>
<script runat="server">
'
' Author: Vivek Jishtu
' Copyright (c) Viamatic Softwares
'
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
'**************************************************
' This acts like a security measure also. So no
' other extension except JavaScript can be downloaded.
'**************************************************

Dim FileName As String = Me.MapPath(Request.QueryString("file") & ".js")
Response.ContentType = "text/javascript"

If Not My.Computer.FileSystem.FileExists(FileName) Then
Response.Write("alert('The file does not exist. Please inform webmaster.');")
Response.End()
Return
End If
'**************************************************
' The javascript never expires so if we get any
' Request for a modified page we send back that
' javascript has not been modified.
'**************************************************
If Request.Headers("If-Modified-Since") <> "" Then
Response.StatusCode = "304"
Response.StatusDescription = "Not Modified"
Response.End()
End If

'**************************************************
' Set the cache such that it does not expire. In
' this example we set it till 22nd Feb 2011.
' You can change the date to whatever year you want,
' any year in the future.
'**************************************************
Response.AddHeader("Last-Modified", DateToHTTPDate(Date.Now))
Response.AddHeader("Expires", "Tue, 22 Feb 2011 05:00:00 GMT")
Response.AddHeader("Cache-Control", "public")
Response.Write("/* prontoCached on " & Date.Now & " */" & vbCrLf)
Response.Write(My.Computer.FileSystem.ReadAllText(FileName))
Response.End()

End Sub

'Source for DateToHTTPDate from http://www.motobit.com/tips/detpg_net-last-modified/
Function DateToHTTPDate(ByVal OleDATE As Date) As String
On Error Resume Next
OleDATE = OleDATE.ToUniversalTime
Return engWeekDayName(OleDATE) & _
", " & Right("0" & Day(OleDATE), 2) & " " & engMonthName(OleDATE) & _
" " & Year(OleDATE) & " " & Right("0" & Hour(OleDATE), 2) & _
":" & Right("0" & Minute(OleDATE), 2) & ":" & Right("0" & Second(OleDATE), 2) & " GMT"
End Function

Function engWeekDayName(ByVal dt As Date) As String
Dim Out As String = ""
Select Case Weekday(dt, 1)
Case 1 : Out = "Sun"
Case 2 : Out = "Mon"
Case 3 : Out = "Tue"
Case 4 : Out = "Wed"
Case 5 : Out = "Thu"
Case 6 : Out = "Fri"
Case 7 : Out = "Sat"
End Select
Return Out
End Function

Function engMonthName(ByVal dt As Date) As String
Dim Out As String = ""
Select Case Month(dt)
Case 1 : Out = "Jan"
Case 2 : Out = "Feb"
Case 3 : Out = "Mar"
Case 4 : Out = "Apr"
Case 5 : Out = "May"
Case 6 : Out = "Jun"
Case 7 : Out = "Jul"
Case 8 : Out = "Aug"
Case 9 : Out = "Sep"
Case 10 : Out = "Oct"
Case 11 : Out = "Nov"
Case 12 : Out = "Dec"
End Select
Return Out
End Function

Public Function DateFromHTTP(ByVal HTTPDate As String) As Date
Dim Swd As String, d As String, Sm As String, y As String, h As String
Dim m As String, s As String, g As String, Out As Date
HTTPDate = LCase$(HTTPDate)

If Mid$(HTTPDate, 27, 3) = "gmt" Then
Swd = Left$(HTTPDate, 3)
d = Mid$(HTTPDate, 6, 2)
Sm = Mid$(HTTPDate, 9, 3)
y = Mid$(HTTPDate, 13, 4)
h = Mid$(HTTPDate, 18, 2)
m = Mid$(HTTPDate, 21, 2)
s = Mid$(HTTPDate, 24, 2)
Out = New Date(y, mFromSm(Sm), d, h, m, s)
Out = Out.ToLocalTime
End If

Return Out
End Function

Function wdFromSwd(ByVal Swd As String) As Integer
Dim Out As Integer
Select Case LCase$(Swd)
Case "sun" : Out = 1
Case "mon" : Out = 2
Case "tue" : Out = 3
Case "wed" : Out = 4
Case "thu" : Out = 5
Case "fri" : Out = 6
Case "sat" : Out = 7
End Select
Return Out
End Function

Function mFromSm(ByVal Sm As String) As Integer
Dim Out As Integer
Select Case LCase$(Sm)
Case "jan" : Out = 1 : Case "feb" : Out = 2
Case "mar" : Out = 3 : Case "apr" : Out = 4
Case "may" : Out = 5 : Case "jun" : Out = 6
Case "jul" : Out = 7 : Case "aug" : Out = 8
Case "sep" : Out = 9 : Case "oct" : Out = 10
Case "nov" : Out = 11 : Case "dec" : Out = 12
End Select
Return Out
End Function
</script>
The VB.net Code

Incase you have the rights to change the expiry of JavaScript on the webserver itself, you can still use the version technique to send out new versions of files using <script src="test1.js?version=0.1" />. The version parameter is there to make it clear, you can also use any random value if you want.


After looking at suggestions from people I guess the best option is to use <script src="test1.js?timestamp={timestamp('test1.js');}" />. This is a simplest way of doing it. To get the timestamp of a file is language/platform dependent. But anytime the file is modified the timestamp would be changed. Using this method you would not have to make changes in the version either.

Technorati Tags: , ,

Wednesday, April 26, 2006

require_once, #include in JavaScript

If you've ever used C/C++, you can include more code by simply using #include and that header file gets included. The same thing goes for PHP, if you divide your program into multiple files you can include the code using include/include_once or require/require_once. If you are looking for something similar in JavaScript, you won't find any way of including more code. This is when I came up with this code, though later on while searching on the net I could see samples using a similar approach. But in any case this might help you to include code in your JavaScript files.

function include(fileUrl) {
var script = document.createElement("script");
var head = document.getElementsByTagName('head').item(0);
script.src = fileUrl;
head.appendChild(script);
}

To include a file in your JS code you can use include("<url of js>"). If you look at the code, we are creating a new <script> tag in the <head> section of the document. This works in Firefox, IE & Opera, and I think it should work in other browsers also, but I have not tested it out.

You can use this approach to do remote scripting (aka AJAX). I will write more about using this for AJAX without using XmlHttp :), I know it would technically not be AJAX, but since AJAX is a hot word these days. It will provide a similar functionality like AJAX but it will be cross domain. That is another article that is coming soon.

Technorati Tags: ,

Monday, April 24, 2006

Template used on this blog

If you want you can use the template used on this blog on your own blog you are free to use it. Goto template and cut and paste this code in that section. You would need to change the links and the images.

If you use this template just link back to this blog. There is a link in the footer, please let it remain there. Other than that you are free to modify whatever you want.
Download the code for the template.

I hope somebody uses it. If you do don't forget to leave a comment and a link back to your blog.

Monday, April 17, 2006

Get a $90 rebate at dreamhost

I guess I can get my webhosting cheap if I get people to signup for dreamhost. I really like them and after a very stupid webhost "GoDaddy", dreamhost comes as a real surprise. They offer WebDAV, Shell accounts, 1TB bandwidth and nearly every other thing the other hosts provide. The best thing that they provide is a shell account. A shell account really gives you a lot of power to do things you can only imagine with the other hosts. They don't have the CPanel as the admin panel. They use their own setup. If you are a developer you will really like the features they provide. Dreamhost is not really for dummies but for a people who know the importance of shell/cvs/subversion while developing. I have not seen any webhost other than dreamhost which provides all three in the regular packages.

If that gets you excited you can get a rebate of $90 on the $120/year hosting plan by using the promo code VIVEK. So you get the yearly package for $30 with all the features plus more. You can also use this link to sign up http://www.dreamhost.com/r.cgi?146010 and I will get some extension in my hosting.

So next time you are looking for a host go with dreamhost. Atleast till I get the kind of service I am getting I would really like people to use their services. Incase I find a better host I will write about it. If you know of a better webhost do let me know. I guess I need another post on GoDaddy soon. Specially about the control panel.

Technorati Tags: , ,

Wednesday, April 12, 2006

Yeh! Pepsi TV kya hai? / What is Pepsi TV?

Again this is not a tech post, its something I was trying to figure out since I saw the advert on TV. And finally I guess I got my answer on CNBC, "I guess" 'cause I don't think the host was too sure but anyhow, Pepsi is not really launching a new channel all they are doing is to promote Pepsi while you drink TV. So nothing earth shattering there, but lets see how that advert turns out to be.

The other advert on these days is the Marinda advert, "Mouth ka sahi use karo" or something like that. That advert is pathetic in every possible sense. It is one of the worst adverts I have seen on TV. It just shows the actor like he is an arrogant idiot too full of himself. I don't mean that the actor is arrogant but the advert just shows it that way.

With all these adverts I cannot forget the new Coke advert with Ashwariya Rai, I really don't get that advert. Atleast that advert is not targeted towards me or people whome I know. It looks like a cheap advert done by a good for nothing agency.

While I am at bashing the adverts I need to shift my focus to Channel [V], they started becoming desi a few years back. At first using third grade actors seemed funny but since the whole channel is being run by these guys, the channel has lost its sheen and are loosing badly to VH1. Instead of starting a new channel with the desi content they destroyed the content they were showing which was quite good. In a way Channel [V] has gone 10 steps backwards.

Tuesday, April 11, 2006

A lot of work and little time

Lately I have been really busy with work. I guess a lot of things have piled up and it seems like they will never be completed. I just hope I can take out a little time soon. Its been a while since I blogged and also I have a few articles that I was going to post here, most of them are no where completion. I guess one of these days I will have to get up and stop being lazy and complete those articles. Its been like a month since I went to Slashdot and about a week since I last visited digg. Currently I feel disconnected :) from the world, without knowing whats the latest that is hapenning around the tech world.

Lets hope I can soon find some time to atleast visit these sites.

Wednesday, April 05, 2006

Red Bull won't give you any wings :)

This is just something I thought I had to write about. I really liked the advert of Red Bull energy drink, with the special reference to the Red Bull gives your wings. I had to try it out, so I shelled out Rs. 75 for one can while a normal can of soft drink costs Rs. 20+.

I tried it out I did not get any wings but yeh! I did have to run to the toilet as i got an upset tummy. I kept waiting for the wings to appear but nothing happend no extra surge of energy. Its a nice way to promote your drink but I don't plan to drink it again even if was for Rs. 15 a can. It was not the best tasting drink I have had so far.