Archive

Posts Tagged ‘Javascript’

Implementing UJS

October 15, 2011 Leave a comment

Unobtrusive Javascript, or UJS for short, is an approach to javascript development that is gaining momentum now that Rails3 and other frameworks are baking in support for it.  I first learned about UJS from watching the Rails3 screencasts shortly after they came out, which was months ago now.  The main concept is nothing new to software development, it’s the old adage of Separation of Concerns.   Javascript has a very different responsibility than your HTML markup. Javascript is used to apply additional behavior on top of existing markup but that doesn’t mean it has to be done in the same line(s) of code or even in the same file.

The DRY (Don’t Repeat Yourself) principle is another benefit of the UJS approach.  If there are common javascript behaviors that are applied throughout your site, shouldn’t they be done in one place rather than scattered about?

In our web application at work we have javascript “widgets” that get applied on almost every page.  The two big ones are a Calendar (DateSelector) and Tabbed interface.

Almost every report in our system has at least a Start and End Date field with a calendar widget used to select dates.

Before UJS

page.html
<form>
<input type=”text” name=”start_date” />
<input type=”text” name=”end_date” />
</form>

...
<script>
window.addEvent('domready', function() {
var start = new DateSelector($('start_date'));
var end = new DateSelector($('end_date'));
});
</script>

This got very repetitive throughout our site and I cringe at how boiler plate it became.  I hated wasting my time and all our other developers time by forcing them to write (copy/paste) these couple of lines of javascript.

After learning about UJS we have re-thought our approach to markup and how javascript is used.

After UJS

page.html
<form>
<input type=”text” class=”date” name=”start_date”/>
<input type=”text” class=”date” name=”end_date” />
</form>

A new global domready event that applies for all input elements with class=”date”:

application.js (using mootools)
<script>
window.addEvent('domready', function() {
$$('input[class=date]').each(function(element) {
var date = new DateSelector(element);
});
</script>

We’ve expanded our UJS support to auto-initialize tabbed interfaces based off pure markup, create async Request objects for form submissions, and validate form input.  This has drastically reduced the amount of javascript our developers write and absolves them of a responsibility that should rightly be separate and unobtrusive to the work they’re trying to accomplish.

By using simple markup attributes (class, id, type) and the support of HTML5 data attributes, you can create both descriptive markup and advanced javascript behaviors to go with it.   A big thanks to Rails3 for making this so easy and moving this approach forward.  If you’re not using Rails, like us, just take these concepts and apply them yourself.

Categories: Uncategorized Tags:

Browsers and Javascript

February 14, 2011 Leave a comment

Browser Connection Limits

We received a complaint from a customer of ours that IE7/8 would become completely unresponsive after using a specific feature of our application for ~15 minutes.   A couple of us were assigned to track down the issue.  Here’s what we learned and how we resolved the issue.

1) All browsers limit the number of connections it will open to a host.
IE6/7 = 2, All modern browsers = 6

For Example:

  • If you are using IE6/7 and you load a page that starts 3 AJAX requests.  Only 2 of them will be sent, queueing the 3rd until a connection becomes available.
  • If you open 4 tabs in IE7, the first 2 tabs will begin loading while the other 2 tabs block waiting for an available connection.
  • If you open 3 tabs (in any browser) and each page performs 3+ AJAX queries, multiple connections will begin to queue up waiting for previous ones to complete.

2) Connection limits make our application look slow

So many of us are under the impression that AJAX solves all our problems.  By loading sections of a page in separate requests we can load the page faster and get users on their way right?  We have failed to realize the drawbacks to this approach.  The example above is from a page of application, which on any action submits at least 3 AJAX requests on page load, sometimes more.  This means that one page in our system is already above the max connection limit for our IE6/7 users.  Now we understand why our IE users complain about speed/performance, because many times requests are blocking waiting for a connection.

3) Not all browsers clean up these connection properly

We finally discovered that if you close a tab in IE7/8 while an AJAX request is running, it does not properly cleanup that connection and now you’re at MAX CONNECTIONS-1.

For IE7 users that means you’re down to 1 connection after the first closed tab and down to 0 after the second.  When IE7/8 get down to 1 connection and you try to load a new page that has 3-4 AJAX requests, each of those are now running in serial because that’s your new max.   “This page is soooo slow!”

All non-Microsoft browsers handle this correctly.  If you have a tab running 6 requests and you close the tab in the middle of those 6 requests, they all get cleaned up and you still have a max of 6 connections available.

Handling the onBeforeUnload Event

So how do you close open connections properly in IE before the window or tab is closed? The onBeforeUnload event fires immediately before a window or tab is closed. In that event you’ll need to manually abort any running requests. Again, this only needs to be done in Internet Explorer. With just a few lines added to the MooTools Request object we had solved our problem.

Out of Place Firing of the onBeforeUnload Event

It was quickly brought to our attention that IE has some further bugs relating to links and unload events.  Certain AJAX requests that were initiated from <a> elements were immediately being aborted (by our fix) when clicked.  It turns out, IE will trigger an onBeforeUnload event when you click any <a> elements with non-local addresses in the href attribute and have an onclick defined.

So where else will we run into this? Well, we often use link elements as placeholders for triggering JavaScript instead of actually linking. One of the side-effects of doing this is the commonly known ‘page jump’ when scrolled any distance down a page. Below, is a list of examples that show the typical methods of getting around the jump including our preffered method.

// jumps to top of page
<a href=”#” onclick=”alert(‘test’);”>Test</a>

// does not jump to top of page
<a href=”#” onclick=”alert(‘test’); return false;”>Test</a> // DON’T USE
<a href=”javascript:void(0)” onclick=”alert(‘test’);”>Test</a> // DON’T USE
<a href=”javascript:alert(‘Test’)”>Test</a> // ACCEPTABLE

// PREFERRED METHOD (shortest, cleanest, valid, and equally effective)
<a onclick=”alert(‘Test’)”>Test</a>

Categories: Uncategorized Tags: