I Can’t Believe It’s Not XMLHttpRequest!

As if my initial amazement of the simplicity of ajax was not enough, as part of my job at Outbrain I have recently come across an even simpler (and in some ways, better) method to implement asynchronous client-side requests to the server. In fact, it is SO simple you would be tempted to use it even when you don’t really need it!

First, I must clarify and say that this other method does not really come to replace the “traditional” AJAX path (involving the use of the native javascript ‘XMLHttpRequest’ object), but simply poses an alternative which might better suit some specific cases. I barely found any refrences to this method on the net. The few places which mentioned it, called it: “Dynamic Script Loading”. Therefore, since this is essentially “uncharted territory”, I shall allow myself to give it a more appropriate name myself, one which would also allude to its purpose. I call it: “Dynamic Pseudo-Script Request” or DPSR.

DPSR is basically a utilization of an old JS feature of browsers: The ability to dynamically create a script element on the client-side at runtime. Since <script> elements support external URLs (as their ‘src’ attribute), this opens the door to an endless world of possibilities. <script> elements have the benefit of being able to initiate requests to ANY server as well as executing the response (as long as it conforms to the syntax of javascript, and to be on the safe-side – as long as the content-type is: “text/javascript”). If we could “cheat” the element into running server-side code (which isn’t really a JS file), we could perform any action we want – asynchronously (with parameters in the URL), and even have the ability to dynamically handle the response, if we choose to. The browser doesn’t “care” what happens when it initiates the request, it only cares about the response (of which we have total control).

For example, take the following scenario: We have an online store (http://example.mystore.com), which allows users to add items to their ‘shopping cart’. Now, naturally, we wouldn’t want an action like this (which involves sending data to the server) to have any disruptive effect on the user’s experience. We don’t want to take him anywhere, we don’t want to submit any forms. We just want a simple “call” to be made: http://example.mystore.com/addItem?id=766118. Now, for the sake of this example – let’s assume that this store is insanely popular, and that it’s entirely possible for an item to be sold-out in the time-frame between its presentation to the user – and the user’s action. Also, let’s assume there’s a limit to the number of items any user can purchase.

If we want the user to feel comfortable (and be able to cope with this insane shopping spree), we should allow him to “seamlessly” add items to his cart without affecting anything else on his browser – except for the result of the action itself. This is where DPSR comes in.

<script type=”text/javascript”>

function callBackFunc(status) {

switch(status) {

case 1: break;

case 2:alert(‘item sold-out!’);break;

case 3:alert(‘shopping cart full’);break;

}

}

function addItemToCart(id) {

var newSE = document.createElement(“script”);

newSE.src=”http://example.mystore.com/addItem?id=&#8221; + id +”&method=callBackFunc”;

document.body.appendChild(newSE);

}

</script>

<body>

. . .

<a href=”javascript:void(0)” onclick=”addItemToCart(766118)”>Add to shopping cart</a>

. . .

</body>

What happens here is that when we add an item, a script element is planted on the page, with a URL that runs some server-side code. This code returns a javascript response : ” callBackFunc( … ); “. Because the browser was expecting javascript and we gave it what it wants, it would kindfully execute it for us. Simple but ingenious. Granted, this code could be made much more elegant. We could make sure that script elements replace each other rather than be added one after the other ad infinitum; we could make a more user-friendly handler for the result; etc…

The main advantages of XMLHttpRequest over DPSR is support for HTTP headers (when things go wrong and we get 500, 503, 404, etc.), out-of-the-box support for XML responses, the ability to make POST requests, and all the benefits of having a fully functional JS object. DPSR, however, enables a straightforward approach that is cross-domain , cross-browser, and is more light-weight. It’s simple to integrate in your application, and since it’s not an object, we can easily return ANY callback function we want, which gives us a great deal of flexibility.

The main drawback of XMLHttpRequest, in my eyes, is that the flow that results is less intuitive to comprehend and manage. For example, we cannot easily manipulate the VIEW (i.e the page from which we initiated the call) after the response arrives, without hard-coding this behavior into the callback handler. This is not only inflexible, but also creates a dependency between the AJAX logic and the view layer. For example, if we have a re-usable piece of DHTML – such as a registration form, we don’t want our ajax function to “know” about the page we placed that form in. Instead, we want each page to be able to have a different implementation of the callback function, and we want to be able to TELL the server what’s the name of the callback function we want it to use (and wrap the result in).

The main drawback of DPSR, I think, is that it forces you to manipulate the DOM. This, however, is obviously very easy to work around.

Feature
XMLHttpRequest
DPSR
HTTP Status
Supported
Not Supported
Cross-Domain
Requires server-side workaround
Supported
Cross-Browser
Requires browser sniffing
Supported
Callback Functionality
Supported; flow is confusing; unflexible
Supported; simple flow; flexible
XML Response
Supported
Requires Handling
POST method
Supported Not Supported
Tidyness Clean Messy (DOM manipulation)

Generally speaking, I think it would be safe to say that XMLHttpRequest is better suited for data retreival, while DPSR serves as an excellent solution for data manipulation (and for very simple calls, such as nickname-availability checks in registration forms).

About these ads

6 Responses to “I Can’t Believe It’s Not XMLHttpRequest!”

  1. Interesting. We’ve long had thumbnail generation plugins to which we pass URLs and they return the thumbnail image data.

    This technique is similar to that, the only difference is that we’re sending back javascript.

    Although you can also work around XHRequests by using hidden iframe submits (that also supports POST requests), it’s best to stick with the standards and use XHR. The web’s already a huge standards mess, no need to muck it up even further :)

  2. klayhamn Says:

    I agree that standardization is very important. However, as far as anyone’s concerned, this completely complies with the standard: all browsers support external JS files to be fetched dynamically, which is all we need for this method. Personally, my problem with XHR is that forces coupling between your client-side logic and the view (the ajax method has to know about the page in order to manipulate it correctly upon response from the server). This is just part of its restrictive and unintuitive event flow.

  3. Hmm … callback functions are a pretty intuitive flow for most people. Even you’ve defined a callback function in the DPSR method.

    All client side manipulation is done via the callback function, which is true in your case as well. So the client side logic in DPSR is coupled with the view as well, right?

    And anyway, the view layer on the Web comprises of 3 sections; Structure (HTML), Presentation (CSS) and Behavior (Javascript), so I’m afraid Javascript is a core part of the view layer of a post Web 2.0 web site.

    Cheers!

  4. klayhamn Says:

    Jaffer – I didn’t mean that the callback flow is not intuitive. Only that a “regular” ajax function is usually tied to the callback function. To do something similar to what I did here with DPSR (passing the callback function name as a parameter) in XHR – you must have some sort of eval() going on in your callback function, which, as we all know, is evil :) Otherwise, you end up with a “hard-coded” flow – the callback function is tightly coupled to the original ajax call!

    And yes, obviously, you can’t have a true DOM manipulating callback function that isn’t coupled with the view. But separating the callback from the call itself, gives you greater freedom and more independent code. This means the CALL can remain the same, but the callBACK would change to match the appropriate behavior for a certain structure/presentation.

    Anyway, obviously the differences between XHR and DPSR is subtle, but I still think they each have their strengths and weaknesses, which make them suitable for different purposes.

  5. You lost me when you mentioned there must be some sort of eval in an XHR callback. I’ve been using AJAX for years, designed custom event handling engines and I’ve never had to use eval. Can you give an example?

    I agree that the differences are subtle, but the one reason why I’d choose standard AJAX over DPSR is error handling and getting the HTTP response states.

  6. klayhamn Says:

    Sorry – I’ll try to make myself clearer :) Normally, you are right – there’s no eval. But if you want to have a dynamic callback functionality, where actually you have more than one possible handler for *the same* ajax call (maybe a different handler for different pages, or several handlers for the same page), you have to return the server response in a javascript form. Otherwise, the flow is controlled – essentially – by what the ajax call defines. And that means the ajax call and the callback handler are both tightly coupled in a linear flow.

    Therefore, as mentioned above, to implement the DPSR flexibility in XHR, you have use eval on a javascript response – OR – to return (in addition to the normal response) some value that would be used some sort of a “dispatcher” (switch(whereToGO){case 1:…case2:… } etc.)
    Again, not impossible, but much simpler with DPSR. You can have a multitude of callback handlers for the same call, and your flow can diverge in many paths dynamically.

    You’re right about the error handling. That’s why I think DPSR is better suited for performing data-manipulation when the response is actually very lightweight, and is mostly used to indicate to the client the success/failure of his action (and continue accordingly).

    If you’re dealing with a lot of data (such as financial reports) or when you need a lot of control over the communication (when you HAVE to know if a call failed and why, or if you need the ability to abort() ), no doubt it’s better to use XHR.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: