Over the past several years, JavaScript has gone from being an afterthought and occasional object of derision to being the single most important language on the Web. If one factor could claim to be the instigator of that remarkable growth, it's the rise of Ajax-based application development.
Ajax, defined simply, is a development and design pattern that allows a website or application to update the screen with live data without the aid of a page refresh. This functionality creates a smoother, more desktop-like experience.
The history of Ajax is similar to many other apparent overnight sensations. Although Ajax seemed to come out of nowhere, in reality it had been percolating for a while. Several years of work spread across the Web went into creating the tools and patterns that came together under the Ajax banner. Throughout the dHTML era of the original Internet bubble and into the dark years after the dot-com crash, developers around the world were unlocking the unexpected power of JavaScript to bring new and exciting application patterns to the web.
The first and most important piece of the Ajax puzzle was the
XMLHttpRequest (XHR) API. XHR is a JavaScript
API used to transfer data messages between a web browser and a web server.
It allows the browser to use an HTTP POST (to
pass data to the server) or GET request (to
access data from the server behind the scenes.) This API is the core of
most Ajax interactions and one of the foundation technologies of modern
web development.
It's also the best gift the Microsoft® Internet Explorer® team ever gave the Internet.
It's true. XHR first appeared in Internet Explorer version 5 way back in 2000. Originally written by Alex Hopmann as a Microsoft® ActiveX® control, XHR was created for use with Microsoft Outlook® Web Access, designed to smooth out the interactions between the advanced (for the time) front-end interface and Microsoft Exchange Server.
Although a software package from Microsoft doesn't exactly count as "humble beginnings," XHR has certainly grown well beyond the limited scope of that one initial product. It has since been implemented in every major browser and has even been adopted as a W3C standard.
Beyond Microsoft's implementation, several other companies made forays into the proto-Ajax realm. Although many were experimenting with these technologies, two are especially worth pointing out—one because it's an interesting and oft-cited footnote to the development of Ajax, and the other because it's an Internet giant that truly brought these technologies to the masses.
Oddpost was a premium web-based email client that launched in 2002. It leveraged many now-familiar patterns. In design and interaction, it was reminiscent of a desktop mail client. Under the hood, it used a concept the developers called DataPacks to transfer small chunks of data from the server to the browser. It made for a novel experience.
Oddpost was eventually bought by Yahoo! and became the basis for a revamped Yahoo! Mail.
Google Maps, Google Suggest, Gmail, and one important article
The real change started a couple of years later with the Gmail, Google Suggest, and Google Maps services. All three leveraged Ajax techniques heavily and generally set the web development world on fire. The responsiveness and interactivity were novel for the general public. Buzz quickly grew around the new Google applications.
Not many people knew it, but things were about to get even more exciting in the web development world, however. At the time, people knew something new and exciting was going on in web application development. For a time, this "something" lacked focus.
All it took was a single article to set it all in motion.
On 18 February 2005, Jesse James Garrett, co-founder and president of Adaptive Path, wrote an article entitled "Ajax: A New Approach to Web Applications" (see Resources). In it, he describes the trend in web application design development that people had been seeing with apps like Gmail and Google Maps. He called it "a fundamental shift in what's possible on the Web."
He also gave the pattern its name—an important moment, as it focused attention on this new trend and gave everyone, even non-technical folks, something to grab onto when discussing the latest and greatest in the world of web development. In the article, he described Ajax—the technology—this way:
Defining Ajax
Ajax isn't a technology. It's really several technologies, each flourishing in its own right, coming together in powerful new ways. Ajax incorporates:
- Standards-based presentation using XHTML and CSS
- Dynamic display and interaction using the Document Object Model
- Data interchange and manipulation using XML and XSLT
- Asynchronous data retrieval using XMLHttpRequest
- JavaScript binding everything together
Although this technical description is in some ways outdated, the basic pattern remains intact: HTML and CSS represent the data and style, the DOM and associated methods allow the page to be updated in real time, XHR allows for communication with the server, and JavaScript orchestrates the whole show.
The overall effect of the article has been monumental. It represents a rare occasion where immense hype met with a waiting well of creativity and energy and set off a revolution. Adopted by the new breed of start-ups that had begun to pop up across the world, Ajax was quickly pushed to the front of the line of web development paradigms. Ajax went from a vague trend in search of a marketing strategy to a key component of modern web design and development.
One of the key drivers of Ajax-based development was the evolution and adoption of several full-featured JavaScript libraries. With the exception of experienced JavaScript developers, few people actually understood the underlying technology of Ajax. So even though much of the in-browser interaction and animation had been figured out to frivolous excess in the dHTML era, this limited pool of experienced JavaScript engineers led to a major gap between demand for Ajax-based sites and the supply of people who could code such an interface from scratch. Libraries like Prototype, Dojo, and jQuery helped fill that gap in a big way by providing ready-to-use interactions and animations as well as patching cross-browser differences and improving on core JavaScript API shortcomings.
Asynchronous JavaScript and even more JavaScript (object notation)
One of the biggest changes in the Ajax landscape from the time of the original post to the present day is the introduction of JSON, a JavaScript-based data transport. Offering smaller file sizes and the convenience of JavaScript-native access (as opposed to the cumbersome DOM-based methods and properties used with XML), JSON was quickly adopted by developers as the data transport of choice. JSON has since been pulled into the recently minted 5th Edition of the ECMAScript specification.
One noteworthy enhancement to the original JSON proposal is JSON+Padding
(JSONP). As you'll see, the
XMLHttpRequest object has a strict security
model that allows communication only with the same domain and protocol as
the requesting page. JSONP creates a clever way around this cross-domain
restriction by wrapping the JSON response in a user-defined callback
function or variable. After you add the JSON script to the document, this method provides instant access to the data
within. This pattern is
common these days, with many larger web services adopting the practice to
allow for mash-ups and other content syndication.
Despite its popularity, however, JSONP presents an obvious vulnerability for malicious code. Because the injection of a script tag from a third party allows for potentially anything to go on the hosting page, there's incredible potential for mischief if a data provider is compromised or if the hosting site is not careful about the resources introduced into the page.
Now that you have some of the history, explore the technology that makes all of this magic happen. Because the generic JavaScript API is paved over by libraries, it is illuminating for even experienced developers to take a look at what's under the hood.
The XMLHttpRequest API and features
Although there are alternative techniques to get data back from the server, XHR remains at the heart of most Ajax interactions. An XHR interaction has two components: the request and response. I'll describe each in turn.
As mentioned, the original XMLHttpRequest object
has a strict security model. This same-origin policy allows for
communication only with exactly the same host, protocol,
and port as the requesting page. This means that communication between
different domains (example.com and example2.com), different hosts
(my.example.com and www.example.com), different protocols
(http://example.com and https://example.com) are all forbidden and will
produce an error accordingly.
With the development of the second version of the XHR object, the new Cross-origin Request Protocol work being done at the W3C, and strong implementation work being done by browser vendors, a mechanism for cross-domain requests is now available in Internet Explorer 8+, Mozilla Firefox 3.5+, Apple Safari 4+, and Google Chrome. It's been slow to gain momentum, but with a specific "Origin" header sent in the request
Origin: http://example.com |
and the server configured to send back a matching "Access-Control-Allow-Origin" header,
Access-Control-Allow-Origin: : http://example.com |
it's now possible to do two-way communications using the XHR object across domains.
There are four methods on the request side:
open()initiates the connection to the server. It takes several arguments:method. The HTTP method to use (This is going to be eitherPOSTorGET)url. The requested URLasync. An optional Boolean parameter that indicates whether the request is asynchronous (This argument defaults to True)user. An optional user name to use for authenticationpassword. An optional password to use for authentication
setRequestHeader()sets headers for the request. It takes two arguments: a header and its associated valuesend()sends the request. This method can take an optional argument containing the body of aPOSTrequestabort()aborts the request
The response also has several attributes and methods:
status. The standard HTTP status of the request (for example,200would be returned for a successful request)statusText. Includes the full response string returned by the web server, including the response text (for example,304 Not Modified)getResponseHeader()Returns the text of a specific header; takes the name of the desired header as a single argumentgetAllResponseHeaders(). Returns the text of all response headersresponseTextA string representation of the response bodyresponseXMLAn XML representation of the response body—a document fragment with a DOM and all associated DOM methods
Once instantiated, the XMLHttpRequest object has
any of five states, represented by the following values:
- 0: UNSENT. Indicates that the object has been created
- 1: OPENED. Indicates that the
open()method has been successfully invoked - 2: HEADERS_RECEIVED. Indicates that the headers from the request have been received
- 3: LOADING. Indicates that the body of the response is being downloaded
- 4: DONE. Indicates that the request is complete but does not indicate whether the request was successful or returned an expected value (Consult the response and standard HTTP headers to gauge the health of the request)
Before we look at some popular libraries, walk through a couple of raw JavaScript examples to see the core technology at work. All of the following examples are available for download (see Download) and can be run on any web server running PHP. All examples manipulate the simple document seen in Listing 1.
Listing 1. The sample HTML document
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Simple Ajax Example</title>
<meta name="author" content="Rob Larsen">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="_assets/css/style.css">
</head>
<body>
<div id="main">
<h1>Simple Ajax Example</h1>
<p><strong id="activate">Click here</strong>
and content will be appended after this paragraph</p>
</div>
<script src="_assets/js/ajax.js"></script>
</body>
</html>
|
Listing 2 illustrates a simple
GET request, which processes the
responseXML. This is a prototypical Ajax
interaction from the early days of the technology. It works in all modern
browsers as well as Internet Explorer versions 7 and 8.
Listing 2. A basic Ajax function
/*
Here's a basic Ajax function
*/
var ajax = function( opts ) {
/*
We have an options argument.
In addition, we want to have some smart defaults.
*/
opts = {
//Is it a Get or Post
type: opts.type || "POST",
//What URL are we going to hit?
url: opts.url || "",
//What do we do with the data
onSuccess: opts.onSuccess || function(){},
//what kind of data do we expect?
data: opts.data || "xml"
};
//create a new XMLHttpRequest
var xhr = new XMLHttpRequest();
//Open the connection to the server
xhr.open(opts.type, opts.url, true);
/*
When the ready state changes
fire this function
*/
xhr.onreadystatechange = function(){
//readyState 4 is "done"
if ( xhr.readyState == 4 ) {
/*
do some simple data processing
There are two components to the returned object-
responseXML and responseText.
Depending on what we're doing we'll need one or the other.
*/
switch (opts.data){
case "json":
//json is text
opts.onSuccess(xhr.responseText);
break;
case "xml":
//XML retains the structure/DOM
//It's passed in whole.
opts.onSuccess(xhr.responseXML);
break;
default :
//Everything else will get TXT
opts.onSuccess(xhr.responseText);;
}
}
};
//close the connection
xhr.send(null);
}
//here's our simple function
var ajaxSample = function(e){
//Simple callback adds some text to the page
var callback = function( data ) {
document.getElementById("main").innerHTML +=
"<p>"
+data.getElementsByTagName("data")[0].getAttribute("value")
+"</p>";
}
//And here's our Ajax call
ajax({
type: "GET",
url: "_assets/data/ajax-1.xml",
onSuccess: callback,
data : "xml"
})
//prevent the default action
e.preventDefault();
}
//Wire everything up
document.getElementById("activate").addEventListener("click", ajaxSample, false);
|
You can see the original ActiveX object in action in Listing 3. If the native implementation doesn't exist, you use a
Try... Catch block to loop through potential
references to the object in different versions of Internet Explorer. This
full, cross-browser implementation is compatible with Internet Explorer
versions as old as version 5.
Listing 3. A cross-browser Ajax script
var ajax = function( opts ) {
opts = {
type: opts.type || "POST",
url: opts.url || "",
onSuccess: opts.onSuccess || function(){},
data: opts.data || "xml"
};
/*
Support for the original ActiveX object in older versions of Internet Explorer
This works all the way back to IE5.
*/
if ( typeof XMLHttpRequest == "undefined" ) {
XMLHttpRequest = function () {
try {
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
}
catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
}
catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {}
throw new Error("No XMLHttpRequest.");
};
}
var xhr = new XMLHttpRequest();
xhr.open(opts.type, opts.url, true);
xhr.onreadystatechange = function(){
if ( xhr.readyState == 4 ) {
switch (opts.data){
case "json":
opts.onSuccess(xhr.responseText);
break;
case "xml":
opts.onSuccess(xhr.responseXML);
break;
default :
opts.onSuccess(xhr.responseText);;
}
}
};
xhr.send(null);
}
var ajaxSample = function(e){
var callback = function( data ) {
document.getElementById("main").innerHTML += "<p>"
+data.getElementsByTagName("data")[0].getAttribute("value")
+"</p>";
}
ajax({
type: "GET",
url: "_assets/data/ajax-1.xml",
onSuccess: callback,
data: "xml"
})
e.preventDefault();
}
document.getElementById("activate").addEventListener("click", ajaxSample, false);
|
Listing 4 shows a pattern that is more common today: taking
the JSON-formatted responseText and parsing it
into a native JavaScript object. This code illustrates the relative
simplicity of dealing with JSON data. When you compare this listing to the
occasionally indirect and verbose methods needed to manipulate XML data,
it's clear why JSON is the data transport of choice for so many
developers.
Listing 4. Using JSON
var ajax = function( opts ) {
opts = {
type: opts.type || "POST",
url: opts.url || "",
onSuccess: opts.onSuccess || function(){},
data: opts.data || "xml"
};
var xhr = new XMLHttpRequest();
xhr.open(opts.type, opts.url, true);
xhr.onreadystatechange = function(){
if ( xhr.readyState == 4 ) {
switch (opt.sdata){
case "json":
opt.onSuccess(xhr.responseText);
break;
case "xml":
opt.onSuccess(xhr.responseXML);
break;
default :
opt.onSuccess(xhr.responseText);;
}
}
};
xhr.send(null);
}
var jsonSample = function(e){
var callback = function( data ) {
//here, the data is actually a string
//we use JSON.parse to turn it into an object
data = JSON.parse(data);
/*
we can then use regular JavaScript object references
to get at our data.
*/
document.getElementById("main").innerHTML += "<p>"
+ data.sample.txt
+"</p>";
}
ajax({
type: "GET",
url: "_assets/data/json-1.json",
onSuccess: callback,
data : "json"
})
e.preventDefault();
}
document.getElementById("activate").addEventListener("click", jsonSample, false);
|
All of the remaining listings (Listings 5-11) use JSON data.
Listing 5 provides a simple JSONP example. As you can see, it avoids XHR entirely and simply appends a script with a callback argument. The callback is returned, wrapping the data object in executable JavaScript code.
Listing 5. JSONP data
var callback = function( data ) {
document.getElementById("main").innerHTML += "<p>"+ data.sample.txt +"</p>";
}
var jsonpSample = function(e){
//create a script element
var jsonp = document.createElement("script");
//give it a source with the callback name appended in the query string
jsonp.src= "_assets/data/jsonp.php?callback=callback";
//add it to the doc
document.body.appendChild(jsonp);
e.preventDefault();
}
//wire up the event
document.getElementById("activate").addEventListener("click", jsonpSample, false);
|
For most developers, the guts of an Ajax request are interesting only in an
academic way. Most of their real work is done in the context of one or
more JavaScript libraries. In addition to patching over any cross-browser
incompatibilities, libraries offer features built on top of the basic API.
The following examples show GET and
POST examples from three popular libraries to
illustrate the different APIs.
Let's start with examples from the popular jQuery library. jQuery's Ajax
function has been recently rewritten to include several advanced features
that lie outside of the scope of this article, but the common feature of
all jQuery Ajax requests is the presence of a configuration object passed
in as an argument to the function. Also, note that jQuery has several
convenience methods, like $.post and
$.get, which are shortcuts to common request
configurations.
Listing 6 shows the concise code required to get data using jQuery.
Listing 6. A jQuery GET request
/*
callback is a simple function that will be run
when the data is returned from the server
*/
var callback = function( data ) {
/*
it just adds a little bit of text to the document
data is the JSON object returned by the server.
*/
$("#main").append($("<p />").text(data.sample.txt));
}
/*
Wire up the ajax call to this click event
*/
$("#activate").click(
function(){
//call $.ajax with a configuration object
$.ajax({
//it's just a get request
type: 'get',
//we're looking for this URL
url: '_assets/data/json-1.json',
//Our cool callback function
success: callback,
//it's going to be JSON
dataType: "json"
})
}
)
|
Listing 7 illustrates posting and retrieving a simple JSON object. Of note is the use of the native JSON object to parse the incoming data. The jQuery documentation talks about the explicit need to augment non-supporting browsers with the JSON2.js script.
The inclusion of an explicit error handler enables the graceful handling of both successful and unsuccessful requests. jQuery's error state takes three arguments, including the XHR object itself, which allows for robust error handling.
Listing 7. A jQuery POST
/*
this is the object we're going to post
*/
var myMessages = {
positive : "Today is a good day",
negative : "Today stinks",
meh : "meh"
}
var callback = function( data ) {
$("#main").append($("<p />").text(data.positive));
}
/*
Setting up a simple error handler.
It doesn't do much.
It's just nice to illustrate error handling.
*/
var errorHandler = function( xhr, textStatus, errorThrown ){
throw new Error("There was an error. The error status was " + textStatus );
}
/*
Here's where the action happens.
Attach an event to out simple button.
*/
$("#activate").click(
function(){
//call $.ajax with a configuration object
$.ajax({
//we're sending data to the server
type: 'POST',
//this is our URL
url: '_assets/data/post-responder.php',
/*
This is our data, JSON stringified
jQuery expects to use native JSON
or JSON2.js in unsupported browsers
*/
data: JSON.stringify(myMessages),
//Here's where we set up our callback function
success: callback,
//The data expected from the server
dataType: "json",
//And our simple error handler
error : errorHandler
}
)
}
);
|
Dojo is far more than the simple Ajax request/DOM manipulation illustrated in the examples that follow. It's really built for hardcore application development. That said, it's still interesting to look at the API in this way.
Note the two separate "Ajax" functions:
xhrGet and xhrPost.
Also, pay attention to the use of the Dojo JSON utility to parse the
incoming data. Listing 8 shows a
GET example.
Listing 8. A Dojo GET request
var callback = function( data ) {
//note the document.getelementById alias
dojo.byId("main").innerHTML += "<p>"+ data.sample.txt +"</p>";
}
var getData = function(){
//xhrGet is for get requests
dojo.xhrGet({
//the URL of the request
url: "_assets/data/json-1.json",
//Handle the result as JSON data
handleAs: "json",
//The success handler
load: callback
});
}
// Use connect to attach events
dojo.connect( dojo.byId("activate"), "onclick", getData );
|
Listing 9 shows a Dojo
POST, including the configuration of an error
handler.
Listing 9. A Dojo POST
var myMessages = {
positive : "Today is a good day",
negative : "Today stinks",
meh : "meh"
}
var callback = function( data ) {
dojo.byId("main").innerHTML += "<p>"+ data.positive +"</p>";
}
var errorHandler = function(){
throw new Error("We dun goofed.")
}
var postData = function(){
//not surprisingly xhrPost is for POST
dojo.xhrPost({
// The URL of the request
url: "_assets/data/post-responder.php",
//This will be JSON
handleAs: "json",
//Set the headers properly
headers: { "Content-Type": "application/json; charset=uft-8"},
//Use Dojo's JSON utility
postData: dojo.toJson(myMessages),
// The success handler
load: callback,
// The error handler
error: errorHandler
});
}
// Use connect to attach events
dojo.connect( dojo.byId("activate"), "onclick", postData );
|
The YUI library presents a slightly different pattern than the previous
two. For one thing, YUI returns the entire XHR object, not just parsed
data, which allows for more precise manipulation of the returned data and
visibility into the entire request. It also means that the developer is
responsible for knowing the ins and outs of the XHR object itself. As an
aside, it also shows the usage of the YUI module loader
use(), which is noteworthy even if it's not
directly related to Ajax (except for loading the
io module). Listing 10
takes a list of YUI modules, and then a callback function as arguments.
Once run, it creates a download package from the Yahoo! Content Delivery
Network (CDN) that contains
all the modules required in a single, CDN-based download.
Listing 10. A YUI GET request
// Create a new YUI instance and populate it with the required modules.
YUI().use('node','event', 'json', 'io', function (Y) {
var callback = function( id, xhr ) {
var data = Y.JSON.parse(xhr.responseText);
Y.one('#main').append("<p>"
+ data.sample.txt
+"</p>");
}
Y.one("#activate").on('click',
function(){
Y.io( '_assets/data/json-1.json', {
//This is actually the default
method: 'get',
on: {success: callback}
})
}
)
});
|
One interesting stylistic choice presented in the
POST example in Listing
11 is the further separation of all the response functions into
the on object.
Listing 11. A YUI POST
YUI().use('node','event', 'json', 'io', function (Y) {
var myMessages = {
positive : "Today is a good day",
negative : "Today stinks",
meh : "meh"
}
var callback = function( id, xhr ) {
var data = Y.JSON.parse(xhr.responseText);
Y.one('#main').append("<p>"
+ data.positive
+"</p>");
}
var errorHandler = function( id, xhr){
throw new Error("There was an error. The error status was "
+ xhr.statusText
+".")
}
Y.one("#activate").on('click',
function(){
Y.io( '_assets/data/post-responder.php', {
method: 'post',
//Use the Y.JSON utility to convert messages to a string
data : Y.JSON.stringify(myMessages),
//All response methods are encapsulated in
//the on object
on: {success: callback,
failure: errorHandler }
})
}
)
});
|
As you can see, the basic patterns are the same across most of the listings. With the exception of supporting ActiveX controls and the JSONP example, they all cover basically the same ground, with different API variations laid on top of the core JavaScript interaction.
Note that all of the libraries offer a
great number of features beyond the basic interactions outlined here.
Although the majority of the Ajax work you're likely to do can be
handled by straightforward GET and
POST requests, it's useful to familiarize
yourself with some of the advanced features in your library of choice.
Hopefully, with the basics in hand and a little peek under the hood, you'll be confident in implementing Ajax interactions in your own sites or applications. As with any technology, the best way to learn about something is to play around with it, so grab the code samples, dive in, and get your hands dirty. As the past few years have proved, it's well worth the effort.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample Ajax code for this article | sample-ajax-code.zip | 18KB | HTTP |
Information about download methods
Learn
- Read Alex Hopmann's The Story of
XMLHttp.
- Read the Jesse James Garret's post, Ajax: A New Approach
to Web Applications.
- Visit JSON.org.
- See JSON standardized in the ECMA-262 ECMAScript Language Specification 5th edition (December
2009).
- Check out the The
XMLHttpRequest 2 specification.
- Learn more about the W3C's Cross-origin
Resource Sharing work.
- Read Nicholas Zakas' examination of cross-domain Ajax.
- Read more about using Ajax
with Dojo.
- Learn more about YUI3: IO.
- Follow the author, Rob Larsen, on Twitter.
- The Web development zone
specializes in articles covering various Web-based solutions.
- Stay current with developerWorks' technical events and webcasts.
-
developerWorks on-demand demos: Watch demos ranging from product
installation and setup for beginners to advanced functionality for
experienced developers.
- Follow developerWorks on
Twitter.
Get products and technologies
- Read about JSONP.
- Check out the
jQuery.ajax()jQuery API. - Learn more about
jQuery, the write-less, do-more
JavaScript library.
- Check out the Dojo Toolkit.
- Get your hands on
the YUI library.
Discuss
- Create your developerWorks profile today and setup a watchlist on Ajax. Get connected and stay connected with
developerWorks community.
- Find other developerWorks members interested in web development.
- Share what you know: Join one of our developerWorks groups focused on web
topics.
- Roland Barcia talks about Web 2.0 and middleware in his blog.
- Follow developerWorks' members' shared bookmarks on web topics.
- Get answers quickly: Visit the Web 2.0 Apps forum.
- Get answers quickly: Visit the Ajax forum.

Rob Larsen has more than 11 years of experience building and designing websites and web applications. Currently, he's an interface architect at Isobar, working with HTML5, CSS3, and other emerging technologies for some of the world's largest brands. Rob writes about the web and web technologies at his blog, HTML + CSS + JavaScript.




