O'Reilly logo

JavaScript Cookbook by Shelley Powers

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

18.9. Using a Timer to Automatically Update the Page with Fresh Data

Problem

You want to display entries from a file, but the file is updated frequently.

Solution

Use Ajax and a timer to periodically check the file for new values and update the display accordingly.

The Ajax we use is no different than any other Ajax request. We’ll use a GET, because we’re retrieving data. We put together the request, attach a function to the onreadystatechange event handler, and send the request:

var url = "updatedtextfile.txt";
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange=updateList;
xmlhttp.send(null);

The fact that we’re doing a direct request on a static text file might be new, but remember that a GET request is more or less the same as the requests we put into the location bar of our browsers. If something works in the browser, it should successfully return in an Ajax GET request...within reason.

In the code that processes the response, we just place the new text into a new unordered list item and append it to an existing ul element:

// process return
function processResponse() {
   if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
     var li = document.createElement("li");
     var txt = document.createTextNode(xmlhttp.responseText);
     li.appendChild(txt);
     document.getElementById("update").appendChild(li);
   } else if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
     alert(xmlhttp.responseText);
   }
}

The new part is the timer. The timer is controlled with start and stop buttons. When the start button is clicked the first time, the code disables the start button first, initiates the first Ajax call, and then starts a timer. There’s a reason for this, as we’ll see in a second:

// timer
function startTimer() {
  populateList();
  timer=setTimeout(timerEvent,15000);
}

The reason we want to make the Ajax call first is that the timer function timerEvent checks the readyState of the XMLHttpRequest object when it’s invoked. If the value is not 4, which means the last request was completed, it doesn’t make another Ajax call. We don’t want to have multiple requests out at the same time:

function timerEvent() {
  if (xmlhttp.readyState == 4) {
    populateList();
  }
  timer=setTimeout(timerEvent, 15000);
}

Lastly, we’ll add a cancel timer event. In this case we’re using a global timer variable, but in a production application we want to use either an anonymous function to wrap everything, or create an object literal to maintain both data and methods:

function stopTimer() {
  clearTimeout(timer);
}

Discussion

The key to using timers with Ajax calls is to make sure that the last call is completed before making the next. By including a check on the XMLHttpRequest object’s readyState property, if the value isn’t 4, we know to skip this Ajax call and just reset the timer for the next go round. We can also put in a check for the request status, and cancel the timer event altogether if we’re concerned about hitting a failing service, over and over again.

When I ran the application that included the solution code, I changed the text file by using the Unix echo command:

$ echo "This is working" > text.txt

And then watched as the text showed up on the page, as shown in Figure 18-1.

Demonstration of updates from polled Ajax calls

Figure 18-1. Demonstration of updates from polled Ajax calls

If you’re planning on using this form of polling with another service, such as against the Twitter API, be aware that if you’re considered abusive of the service, you may get kicked off. Check to see if there are restrictions for how often you can access a service using the API.

Note

Depending on the browser, you may run into caching issues if you access the text.txt file locally. Providing a full URL should prevent this from occurring.

A few years ago, there was interest in a push rather than pull type of Ajax communication. Encompassed under the coined term of Comet, the concept was that the server would initiate the communication and push the data to the client, rather than the client pulling the data from the server. Eventually, the concept led to work in the W3C on a new JavaScript API called WebSockets. Currently only implemented in Chrome, WebSockets enables bidirectional communication between server and client by using the send method on the WebSocket object for communicating to the server, and then attaching a function to WebSocket’s onmessage event handler to get messages back from the server, as demonstrated in the following code from the Chromium Blog:

 if ("WebSocket" in window) {
  var ws = new WebSocket("ws://example.com/service");
  ws.onopen = function() {
    // Web Socket is connected. You can send data by send() method.
    ws.send("message to send"); ....
  };
  ws.onmessage = function (evt) { var received_msg = evt.data; ... };
  ws.onclose = function() { // websocket is closed. };
} else {
  // the browser doesn't support WebSocket.
}

Another approach is a concept known as long polling. In long polling, we initiate an Ajax request as we do now, but the server doesn’t respond right away. Instead, it holds the connection open and does not respond until it has the requested data, or until a waiting time is exceeded.

See Also

See Recipe 14.8 for a demonstration of using this same functionality with an ARIA live region to ensure the application is accessible for those using screen readers. The W3C WebSockets API specification is located at http://dev.w3.org/html5/websockets/, and the Chrome introduction of support for WebSockets is at http://blog.chromium.org/2009/12/web-sockets-now-available-in-google.html.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required