Here comes the fun part—understanding what happens in that code. (Remember that we’ll discuss much more technical details over the following two chapters.)
Let’s start with the file the user first interacts with, index.html
. This file references the mysterious JavaScript file called quickstart.js
, and builds a very simple web interface for the client. In the following code snippet from index.html
, notice the elements highlighted in bold:
When the page loads, a function from quickstart.js
called process()
gets executed. This somehow causes the <div>
element to be populated with a message from the server.
Before seeing what happens inside the
process()
function, let’s see what happens at the server side. On the web server you have a script called quickstart.php
that builds the XML message to be sent to the client. This XML message consists of a <response>
element that packages the message the server needs to send back to the client:
If the user name received from the client is empty, the message will be, “Stranger, please tell me your name!”. If the name is Cristian, Bogdan, Filip, Mihai, or Yoda, the server responds with “Hello, master <user name>!”. If the name is anything else, the message will be “<user name>, I don’t know you!”. So if Mickey Mouse types his name, the server will send back the following XML structure:
The quickstart.php
script starts by generating the XML document header and the opening <response>
element:
The highlighted header line marks the output as an XML document, and this is important because the client expects to receive XML (the API used to parse the XML on the client will throw an error if the header doesn’t set Content-Type
to text/xml
). After setting the header, the code builds the XML response by joining strings. The actual text to be returned to the client is encapsulated in the <response>
element, which is the root element, and is generated based on the name received from the client via a GET
parameter:
The text entered by the user (which is supposed to be the user’s name) is sent by the client to the server using a GET
parameter. When sending this text back to the client, we use the htmlentities
PHP function to replace special characters with their HTML codes (such as &, or >), making sure the message will be safely displayed in the web browser eliminating potential problems and security risks.
Note
Formatting the text on the server for the client (instead of doing this directly at the client) is actually a bad practice when writing production code. Ideally, the server’s responsibility is to send data in a generic format, and it is the recipient’s responsibility to deal with security and formatting issues. This makes even more sense if you think that one day you may need to insert exactly the same text into a database, but the database will need different formatting sequences (in that case as well, a database handling script would do the formatting job, and not the server). For the quickstart scenario, formatting the HTML in PHP allowed us to keep the code shorter and simpler to understand and explain.
If you’re curious to test quickstart.php
and see what it generates, load http://localhost/ajax/quickstart/quickstart.php?name=Yoda
in your web browser. The advantage of sending parameters from the client via GET
is that it’s very simple to emulate such a request using your web browser, since GET
simply means that you append the parameters as name/value pairs in the URL query string. You should get something like this:
This XML message is read on the client by the handleServerResponse()
function in quickstart.js
. More specifically, the following lines of code extract the “Hello, master Yoda!” message:
Here, xmlHttp
is the XMLHttpRequest
object used to call the server script quickstart.php
from the client. Its responseXML
property extracts the retrieved XML document. XML structures are hierarchical by nature, and the root element of an XML document is called the document element. In our case, the document element is the <response>
element, which contains a single child, which is the text message we’re interested in. Once the text message is retrieved, it’s displayed on the client’s page by using the DOM to access the divMessage
element in index.html
:
document
is a default object in JavaScript that allows you to manipulate the elements in the HTML code of your page.
The rest of the code in quickstart.js
deals with making the request to the server to obtain the XML message. The createXmlHttpRequestObject()
function creates and returns an instance of the XMLHttpRequest
object. This function is longer than it could be because we need to make it cross-browser compatible—we’ll discuss the details in Chapter 2, for now it’s important to know what it does. The XMLHttpRequest
instance, called xmlHttp
, is used in process()
to make the asynchronous server request:
What you see here is, actually, the heart of AJAX—the code that makes the asynchronous call to the server.
Why is it so important to call the server asynchronously? Asynchronous requests, by their nature, don’t freeze processing (and user experience) while the call is made, until the response is received. Asynchronous processing is implemented by event-driven architectures, a good example being the way graphical user interface code is built: without events, you’d probably need to check continuously if the user has clicked a button or resized a window. Using events, the button notifies the application automatically when it has been clicked, and you can take the necessary actions in the event handler function. With AJAX, this theory applies when making a server request—you are automatically notified when the response comes back.
If you’re curious to see how the application would work using a synchronous request, you need to change the third parameter of xmlHttp.open
to false
, and then call handleServerResponse
manually, as shown below. If you try this, the input box where you’re supposed to write your name will freeze when the server is contacted (in this case the freeze length depends largely on the connection speed, so it may not be very noticeable if you’re running the server on the local machine).
The process()
function is supposed to initiate a new server request using the XMLHttpRequest
object. However, this is only possible if the XMLHttpRequest
object isn’t busy making another request. In our case, this can happen if it takes more than one second for the server to reply, which could happen if the Internet connection is very slow. So, process()
starts by verifying that it is clear to initiate a new request:
So, if the connection is busy, we use setTimeout
to retry after one second (the function’s second argument specifies the number of milliseconds to wait before executing the piece of code specified by the first argument:
If the line is clear, you can safely make a new request. The line of code that prepares the server request but doesn’t commit it is:
The first parameter specifies the method used to send the user name to the server, and you can choose between GET
and POST
(learn more about them in Chapter 3). The second parameter is the server page you want to access; when the first parameter is GET
, you send the parameters as name/value
pairs in the query string. The third parameter is true
if you want the call to be made asynchronously. When making asynchronous calls, you don’t wait for a response. Instead, you define another function to be called automatically when the state of the request changes:
Once you’ve set this option, you can rest calm—the handleServerResponse
function will be executed by the system when anything happens to your request. After everything is set up, you initiate the request by calling XMLHttpRequest
’s send
method:
Let’s now look at the handleServerResponse
function:
The handleServerResponse
function is called multiple times, whenever the status of the request changes. Only when xmlHttp.readyState
is 4
will the server request be completed so you can move forward to read the results. You can also check that the HTTP transaction reported a status of 200, signaling that no problems happened during the HTTP request. When these conditions are met, you’re free to read the server response and display the message to the user.
After the response is received and used, the process is restarted using the setTimeout
function, which will cause the process()
function to be executed after one second (note though that it’s not necessary, or even AJAX specific, to have repetitive tasks in your client-side code):
Finally, let’s reiterate what happens after the user loads the page (you can refer to Figure 1.7 for a visual representation):
The user loads index.html
(this corresponds to steps 1-4 in Figure 1.7).
User starts (or continues) typing his or her name (this corresponds to step 5 in Figure 1.7).
When the process()
method in quickstart.js
is executed, it calls a server script named quickstart.php
asynchronously. The text entered by the user is passed on the call as a query string parameter (it is passed via GET
). The handeServerResponse
function is designed to handle request state changes.
quickstart.php
executes on the server. It composes an XML document that encapsulates the message the server wants to transmit to the client.
The handleServerResponse
method on the client is executed multiple times as the state of the request changes. The last time it’s called is when the response has been successfully received. The XML is read; the message is extracted and displayed on the page.
The user display is updated with the new message from the server, but the user can continue typing without any interruptions. After a delay of one second, the process is restarted from step 2.