C:\2000S\AJAX.TXT

2005

Ajax: The Page Can Wait Without You

A 2005 name made asynchronous browser applications easier to discuss, while moving ordering, failure and state management into the interface.

7 min readCovers February 2005 naming milestone; 2006 API draftSoftware That Shaped the 2000s

A web application can ask its server a question without making every other activity on the page wait for the answer. That is a simple proposition with a surprisingly large set of consequences. The user may keep typing, change the question, or leave the relevant part of the interface before the reply arrives.

On February 18, 2005, Jesse James Garrett published “Ajax: A New Approach to Web Applications.” He gave a name to an arrangement of existing browser technologies, using Google Suggest and Google Maps as visible examples. The accompanying March questions and answers explicitly denied that Adaptive Path or Google had invented the underlying approach.1

Naming mattered because it made the arrangement easier to discuss. A design conversation could refer to Ajax without listing JavaScript, the document model, styling and network requests every time.

It was a milestone in vocabulary and adoption, rather than the birthday of every mechanism involved. No downloadable product called Ajax was required. The interesting unit was the application architecture: what ran in the page, what required a server and what happened while the two communicated.

Sending isn’t finishing

Consider an invented catalogue search. The page already contains a search box and a results area. Typing a query initiates a request. When a response arrives, a script updates the results area without replacing the entire document.

This separates three events that a whole-page navigation tends to present as one operation: accepting the user’s action, waiting for data and displaying a result. Each event needs its own representation in the interface.

The search box can remain usable during the wait. A loading message can describe the pending operation. Existing results might remain visible, but the application needs to make clear whether they belong to the old query or the new one.

The April 2006 W3C XMLHttpRequest working draft describes asynchronous sending and completion states. It identifies itself as a first draft documenting existing implementations, with interoperability gaps still to address.2

That date boundary matters. A 2006 draft is useful evidence about period API work, but it isn’t a final standard that every 2005 browser already implemented exactly. Its conspicuous unresolved editorial questions are part of the record.

Nor does asynchronous mean that JavaScript executes several calculations simultaneously. The useful distinction here is that starting a network operation needn’t hold the initiating call until its response is complete. How script execution is scheduled is another question.

Two questions can return in the wrong order

Now give the user a short sequence. At time zero they type ca. At 50 milliseconds they add a letter, making the query cat. Our invented server delays the first reply until time 300, while the second arrives at time 150.

The newer result arrives first. At time 150, the page correctly displays results for cat. Then the old ca response arrives. If every response simply overwrites the results area, the page ends with an answer to a question the user is no longer asking.

The response is not necessarily corrupt. The application is applying a valid old answer to the wrong current state. This is an ordering error caused by the relationship between requests and the interface.

Assign each query a monotonically increasing generation number. ca gets generation 1; cat gets generation 2. The page remembers that its latest requested generation is 2.

When a response arrives, compare its generation with the remembered latest generation. Apply generation 2. Discard generation 1 when it arrives later.

Response arrivesQueryGenerationAction
150 mscat2Display
300 msca1Ignore

The timing values and response payloads are invented. Our executable model sorts scheduled responses by arrival time and checks the resulting display. The naive rule ends at ca; the generation rule ends at cat.

A newer query's response arrives before an older one

Original CC0 diagram, 2026. Invented timing and generation model; not a benchmark or recovered application trace.

The improvement has a specific scope. It prevents an older response from replacing the latest requested result. It doesn’t prove that the latest result is accurate, and it doesn’t supply a result if the newest request fails.

If generation 2 never returns, ignoring generation 1 still doesn’t answer cat. The page must explain the failure or let the user retry. A concurrency rule and a useful failure experience are complementary pieces of work.

Fewer requests can be a design choice

A type-ahead search can make a request after every character. It can also wait briefly for a pause. The second choice is often called debouncing: postpone the action while a closely spaced series of inputs continues.

For another invented sequence, the user types at 0, 80 and 160 milliseconds. With a 200-millisecond quiet interval, the scheduled requests at 200 and 280 are superseded. One request runs at 360, assuming no further input.

The cost is a deliberate delay after the last input. The potential benefit is fewer requests for intermediate queries the user never intended to inspect. These teaching times aren’t a measured optimum or a claim about Google Suggest’s historical settings.

Debouncing and response ordering solve different problems. The first changes how often requests begin. The second determines which completed request can update the page. A debounced system can still receive replies out of order when enough time passes between requests.

That distinction makes the application easier to reason about. “Make it less noisy” and “don’t show stale results” are separate requirements. One implementation detail shouldn’t be credited with satisfying both without a check.

A finished request can still be a failed task

The W3C draft distinguishes transfer completion from the HTTP status of the response.2 The application has to inspect more than the fact that something arrived.

A server might return a successful response containing an empty result list. It might return an error response. It might return data in a shape the client cannot interpret. Those cases can all require different messages.

Our teaching catalogue assigns four possible outcomes: pending, results available, successful but empty, and failed. Empty is a legitimate answer to a search. Failed means the application couldn’t obtain or use an answer.

Displaying “no matches” after a network failure is misleading. It converts absence of evidence into evidence of absence. The interface should preserve the distinction even if both outcomes leave the result list empty.

The visible result distinguishes empty from failed

Original CC0 illustration, 2026. General application states, not exact XMLHttpRequest ready-state names.

A retry introduces another question. Repeating a search is usually conceptually different from repeating a purchase or other state-changing operation. An interface that encourages retries needs to know what repeating the operation can do.

This article’s model only searches invented data. It sends no transaction and makes no claim that arbitrary server actions are safe to repeat. The architectural lesson is to attach failure handling to the operation’s meaning, rather than to a generic spinner.

Local work and server work have different authority

Some changes can happen entirely in the loaded page. A script can show a panel or reorganize data it already holds. Other operations need information or a decision from the server.

Suppose a form contains a required name. The browser can warn about an empty field before sending it. That is useful feedback, but the server must still evaluate submitted data according to its own rules.

The browser’s check isn’t a trusted enforcement boundary merely because it looks immediate. A different client can send a different request. The person building the application needs to decide which decisions are conveniences and which decisions determine what the service will accept.

This division also affects saved state. Editing a value on screen is not necessarily saving it. The application should represent the period between a local edit and an acknowledged save, including the possibility that saving fails.

A whole-page form submission didn’t make all of these issues disappear. Ajax made them harder to hide behind a single navigation. The interface could now remain available while several pieces of state occupied different stages of completion.

The page still needs navigation

A dynamic interface can change substantially while its address remains the same. That raises practical questions about bookmarks, the Back button and returning to a particular state.

Garrett’s March Q&A acknowledged that accessibility, compatibility, navigation and security questions required further work. It also clarified that XML wasn’t mandatory and that the approach didn’t automatically improve an experience.1

Those qualifications are a valuable antidote to the name’s apparent certainty. A technique can create flexibility while creating obligations. An application still has to make its state understandable to people who navigate differently or return through a saved address.

The examples here don’t use modern Fetch, promises or a current framework as though they shipped in 2005. Python executes an ordering model; it doesn’t run a historical browser. The original milestone is kept separate from later programming conveniences.

A name for work the page could keep doing

Ajax helped establish a useful design expectation: a web interface could stay present while the network performed part of its work. The next step wasn’t always another complete page.

The ordering example shows the price of that freedom. More than one question can be outstanding. Completion doesn’t establish relevance. A failure isn’t an empty result. An edit isn’t an acknowledged save.

These are ordinary application concerns made visible inside the browser. The name shortened the conversation, but it didn’t shorten the list of things a careful implementation had to remember.

I find the delayed reply the most instructive part. It arrives with perfectly good information, slightly too late to be useful. An application becomes responsive when it can keep working during that delay. It becomes dependable when it also knows what to do with the answer afterward.

Sources

Footnotes

  1. Jesse James Garrett, Ajax: A New Approach to Web Applications, February 18, 2005, with March 13 Q&A, preserved mirror of Adaptive Path’s primary essay. Naming, existing components and explicit qualifications; full essay/Q&A read. ↩ ↩2

  2. W3C, Anne van Kesteren and Dean Jackson editors, The XMLHttpRequest Object, April 5, 2006 working draft. Period API discussion, completion/status and asynchronous sending; unfinished draft, not uniform 2005 browser behavior. ↩ ↩2

software-historyajaxwebdeveloper-tools2000s