The Price of Ajax

This may seem nitpicky, but I am working on an application that will be
used every day, potentially by users with modem connections as slow as
26kbit/sec. I want it to feel snappy even to those users.

So, I’m making heavy use of Ajax and partials. However, I’m concerned
about ajax’s cost of admission. In order to do basic ajaxy things, I
have to include at least:

http://localhost:3000/javascripts/prototype.js?1153328689

in the page. This weighs in at 54k or 20 seconds on a modem.

In addition, say I have a data table with 100 lines and each one has an
ajax link to a destroy method. I end up with 100 instances of something
that looks like this:

Delete

That’s 200 bytes extra per row, or 20k or an extra 8 seconds on a modem.

I am using the output_compression plugin. But tests I have run suggest
that static content, like javascripts, do not get gzip compressed.

Is there a “clean” way to improve this situation, where “clean” means
still doing things the rails way and not going off into my own custom
optimizations? Or is this just the way it is?

Steve B. wrote:

I am using the output_compression plugin. But tests I have run suggest
that static content, like javascripts, do not get gzip compressed.

Just a correction in the interest of accuracy. Although the
output_compression plugin does not compress the javascripts, lighttpd
does as long as compression is enabled in its config.

Steve,

I am using the output_compression plugin. But tests I have run suggest
that static content, like javascripts, do not get gzip compressed.

Is there a “clean” way to improve this situation, where “clean” means
still doing things the rails way and not going off into my own custom
optimizations? Or is this just the way it is?

You may like to look at the Unobtrusive Javascript (UJS) Plugin [1].

From the quickstart guide: “The main purpose of UJS is to help you
remove the JavaScript that normally litters your HTML pages and put it
all away in a neat external JavaScript file that can be cached by the
browser.”

It also encourages one to create a working application without
JavaScript, and then layer on the JavaScript to enrich the interface.
So the app works well for anyone, such as your modem users, who may
have JavaScript disabled.

Hope that helps,
Andy S.

[1] http://www.ujs4rails.com/

or you can use apaches mod_compress to compress the data.

2006/8/27, Steve B. [email protected]:

http://localhost:3000/javascripts/prototype.js?1153328689

Posted via http://www.ruby-forum.com/.


Michael S. [email protected]

www.siebert-wd.de - Gedanken lesen
www.stellar-legends.de - Weltraum-Browsergame im Alpha-Stadium

On Aug 27, 2006, at 7:52 AM, Steve B. wrote:

http://localhost:3000/javascripts/prototype.js?1153328689

in the page. This weighs in at 54k or 20 seconds on a modem.

I was under the impression that most browsers cache references
to Javascript and CSS files. Is that actually the case?

But I hear 'ya! I have an admin page with 100 rows of drap-and-drop +
in-place editing – not only is it a lot of HTML, Safari runs like
its legs are cut off at the knees.

Scott

Thanks, all, for the replies. I continue to be impressed by the
responsiveness of this forum and the way solutions to my problems simply
materialize, seemingly out of nowhere once I ask the right question.

UJS looks like the sort of thing that might make its way into Rails
proper at some point? It was dead simple to install, looks far more
elegant than the usual way, and cut my example line of javascript from:

Delete

to:

Delete

or from 196 bytes per row, to 115. And all I did was follow the simple
installation and config steps on the getting started page. No line by
line editing of my app was necessary to use it.

It added 9k to the included list of javascripts, but that is completely
cacheable and I can live with it.

Michael, yes, I determined that although the output_compression plugin
does not compress the static content, that lighttpd does catch it if you
have it enabled. I believe it is enabled by default. You get about a
4:1 compression, btw.

Scott, I believe files like prototype.js are cached like any other
static content. But not the inline javascript snippets in the page,
whose sizes can add up quickly. My example referred 100 bytes of js
associated with each row of a table. It’s not hard to imagine a
situation where 100 bytes of js is associated with each cell of the
same 100 row, 10 column table.

BTW, anyone know why the image src is set to
/images/delete.png?1156712862 instead of just /images/delete.png?

Regarding the cost of inline javascript, I have come up against the same
issue recently (and I’ve never liked inline javascript all that much
anyway). Now that they’ve solved the onload
woehttp://mir.aculo.us/articles/2006/06/15/solving-the-onload-woeit’s
easy to make
suckerfish http://www.htmldog.com/articles/suckerfish/dropdowns/-like
solutions. For your delete example, you could do something like this:

  • Create a single function that accepts dom element, parses the text
    appropriately and makes the ajax call (using prototype if you wish)
  • Create a separate function that loops through all of the links on
    the page that have a certain class (which prototype makes easy) and
    add an
    onclick event handler that passes the link to the function

For those that hate writing javascript, you can take advantage of the
rails
helpers and get the benefit of external js files by dynamically creating
the
js files. Rails recipes has a good description of this under “Lightning
Fast Javascript Autocompletion” - since it’s just a view, you can use
all of
the remote_function helpers and wrap them in function names.

Steve B. wrote:

BTW, anyone know why the image src is set to
/images/delete.png?1156712862 instead of just /images/delete.png?

Actually, I’m surprised that this wasn’t pointed out… as far as I
know, rails automatically adds a random-ish number to the name of items
that usually get cached (images, stylesheets, javascript files) to
prevent them from being cached by the browser in DEVELOPMENT mode. This
makes the development process easier and less problematic.

You shouldn’t see that in production, so it should be fine!
Cheers
Mohit.

On 8/28/06, Steve B. [email protected] wrote:

or from 196 bytes per row, to 115. And all I did was follow the simple
installation and config steps on the getting started page. No line by
line editing of my app was necessary to use it.

You should be aware (and someone please correct me if I’m wrong) that
using
UJS can significantly slow down performance for pages with large numbers
of
elements.

Granted, I can’t speak from experience for UJS, but I can with Behavior
(
http://bennolan.com/behaviour/), which uses the similar technique of
using
CSS selectors to apply javascript. The slow down occurs because to
selectively apply the javascript the library has to scan (and rescan,
upon
each redraw) your entire DOM to identify those elements it should add
the JS
to.

On most pages, it won’t be a problem. But in our case, we had a page
with
many, many elements, and the slow down and CPU usage was painful.

Again, I could be wrong, but something to consider.

Jake

On 8/28/06, Jake C. [email protected] wrote:

UJS can significantly slow down performance for pages with large numbers of
many, many elements, and the slow down and CPU usage was painful.

Again, I could be wrong, but something to consider.

Jake

I agree that using UJS and a lot of css selectors could lead to poor
performance. However, if you are using some sort of predictable
scheme for the id’s and classes of your elements, you could do some
optimization if things get bad.

For example, if you have a table of 500 rows that all need an onclick
event attached, you can give them all the same class and then try out
some of the different “getElementsByClassName” functions to see what
performs the best. The css selector stuff is powerful, but it can be
slower then a simple function that only takes a css class and a root
node (for where to start the search). A mix of both would probably be
necessary for a page with a lot of events being attached.

To further reduce the file size, you could insert the image tag
dynamically
as well. Which will reduce your html to :

BTW, anyone know why the image src is set to

/images/delete.png?1156712862 instead of just /images/delete.png?

the stuff after the ? is based on the timestamp of the image file (or
other
resource like javascript, css etc.). These resources are usually cached
by
browsers. When you change your image (or css) this number changes which
forces the browser to reload the image. Helps with cases where you’ve
upgraded your css but the users are still using the older version.

Hammed

hi,
you can compress your prototype.js file, there are javascript
compressors on
the web that can strip comments, blank lines, use shorter names, etc…
i had the same problem and saved all in all 100kb by compressing
javascripts.

Heri R.
http://sprinj.com