Progress Bar Using AJAX: Design Details

來源:互聯網
上載者:User
ajax

Progress Bar Using AJAX: Design Details

The sequence diagram below details the participants on both the client and server needed to provide an AJAX progress bar. The details are explained in further detail in the remainder of this document.

Tracking the progress of a server-side operation by a client requires two operations which include:

  1. Negotiate a Task Id: This Id is used by the polling loop to track the progress of the task.
  2. Polling Loop: The polling loop will continue until the task is complete.

Now let us review each of these operations in more detail.

Negotiate a Task Id

An HTML form button onClick event calls a JavaScript function which in turn will create an XMLHttpRequest object and the URL and callback function as may be seen in the JavaScript code snippet below.

function submitTask() {
var url = "task?action=startTask";
var bttn = window.document.getElementById("taskbutton");
bttn.disabled = true;
initRequest(url);
// set callback function
req.onreadystatechange = processInitialRequest;
req.send(null);
}

function initRequest(url) {
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
isIE = true;
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.open("GET", url, true);
}

The url in the code above includes a URL parameter action which is set to "startTask." When the req.send(null); statement is executed the request is sent to the URL "task" The client continues processing page events because the interaction is configured to be an asynchronous HTTP GET with the req.open("GET", url, true); statement.

On the server, a servlet TaskServlet is mapped to the URL "task." When the TaskServlet receive a request containing a parameter "action" with the value of "startTask," a new Task is created as can be seen in the code snippet below.

            if ((action != null) && action.equals("startTask")) {
// this task will take 15 cycles of the counter to complete
Task t = new Task(counter, 15);
taskCounter++;
tasks.put(taskCounter + "", t);
// return intial content
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
PrintWriter pw = response.getWriter();
pw.write("<message&qt;" + taskCounter + "</message>");
pw.flush();
}

The snippet of code from the TaskServlet above shows the TaskServlet creating a new Task object and placing it in a java.util.HashMap with a unique identifier. For this example, an int taskCounter is used to identify each Task.

The taskCounter increments each time a new Task is created. In cases where the progress will be tracked in an environment outside the firewall, more unique identifiers may be necessary to prevent nefarious user from tracking operations they did not initiate.

The taskCounter is the unique id that is returned to the XMLHttpRequest in an XML document. This id is later used to track the progress of the Task when the client polls the TaskServlet. In this example, the TaskServlet has an internal timer running on a thread which sleeps for 2 seconds and increments the variable counter. To simulate a server-side operation this example sets the Task duration be 15 increments of the counter (30 seconds total).

On the client, the response from the TaskServlet is received by the XMLHttpRequest object which calls the processIntialRequest() callback function shown below.

// callback function for intial request to schedule a task
function processInitialRequest() {
if (req.readyState == 4) {
if (req.status == 200) {
var item = req.responseXML.getElementsByTagName("message")[0];
var message = item.firstChild.nodeValue;
// the initial requests gets the targetId
targetId = message;
messageHash = 0;
window.status = "";
createProgressBar();
showProgress(0);
}
var idiv = window.document.getElementById("task_id");
idiv.innerHTML = "Task ID=" + targetId;
// do the initial poll in 2 seconds
setTimeout("pollTaskmaster()", 2000);
}
}

This processInitialRequest() function extracts the task id from the XML document and assigns it to the variable targetId. The function will then initialize the progress bar in the HTML DOM and and show the initial progress of 0. The statement setTimeout("pollTaskmaster()", 2000); is then executed to start the polling loop.

Polling Loop

The polling loop polls the TaskServet using the task id store in the targetId variable until the server-side operation is completed (a response of 100 is returned).

function pollTaskmaster() {
var url = "task?messageHash=" + escape(messageHash) + "&targetId=" + targetId;
initRequest(url);
req.onreadystatechange = processPollRequest;
req.send(null);
}

The pollTaskmaster() function configures the XMLHttRequest object with a URL and callback function. The request is sent to the URL "task" which is mapped on the server to the TaskServlet. The following code in the TaskServlet is responsible for processing the request.

                int percentage = 0;
if (tasks.get(targetId) != null) {
percentage = ((Task)tasks.get(targetId)).getPrecentComplete(counter);
}
if ((messageHash !=null) &&
(Integer.valueOf(messageHash).intValue()) == percentage) {
// nothing has changed
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
PrintWriter pw = response.getWriter();
if (percentage &qt; 100) percentage = 100;
pw.write("" + percentage + "");
pw.flush();
}

In the code above, the Task object is looked up using the unique id (targetId) provided in the request. The Task getPrecentComplete method is called with the current counter to calculate the progress of the operation and the results are returned in an XML document. Note that if the messageHash representing the current percentage of completion being displayed by the client matches the percentage complete of the operation in the Task (indicating no change) the TaskServlet will return an HTTP response code 304 (No Content). This saves time for post processing of the message by the client, time for message generation by the TaskServlet, and bandwidth for transmitting the message.

Upon receiving the response from the TaskServlet the XMLHttpRequest object will call the processPollRequest() to do post processing of the request.

function processPollRequest() {
if (req.readyState == 4) {
if (req.status == 200) {
var item = req.responseXML.getElementsByTagName("message")[0];
var message = item.firstChild.nodeValue;
showProgress(message);
messageHash = message;
} else {
window.status = "No Update for " + targetId;
}
if (messageHash < 100) {
setTimeout("pollTaskmaster()", 5000);
} else {
setTimeout("complete()", 2500);
}
}
}

The HTML DOM is updated by showProgress() function if the req.status HTTP status code is 200. This function will detect if the percentage from the server is complete (100) and stop the polling loop by calling the complete() function. Otherwise, the polling will continue to loop by executing the setTimeout("pollTaskmaster()", 5000); statement following a 5 second delay.

<

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.