AJAX In Action [111]
Alongside the Previously, our command queue sent requests to the server only if there were commands queued up. We would need to modify it now to poll the server even if the queue were empty, in order to receive updates. Implementing this touches upon the code in several places. Listing 6.1 shows the revised CommandQueue object, with the changes in bold. Listing 6.1 CommandQueue object net.cmdQueues=new Array(); b Global lookup net.CommandQueue=function(id,url, onUpdate,freq){ c Extra parameters this.id=id; net.cmdQueues[id]=this; this.url=url; this.queued=new Array(); this.sent=new Array(); Licensed to jonathan zheng Keeping the user informed 219 this.onUpdate=onUpdate; if (freq){ d Polling initializer this.repeat(freq); } this.lastUpdateTime=0; } net.CommandQueue.prototype.fireRequest=function(){ if (!this.onUpdate && this.queued.length==0){ return; } var data="lastUpdate="+this.lastUpdateTime+"&data="; Timestamp requests for(var i=0;i if (this.isCommand(cmd)){ data+=cmd.toRequestString(); this.sent[cmd.id]=cmd; } } this.queued=new Array(); this.loader=new net.ContentLoader( this.url, net.CommandQueue.onload,net.CommandQueue.onerror, "POST",data ); } net.CommandQueue.onload=function(loader){ var xmlDoc=net.req.responseXML; var elDocRoot=xmlDoc.getElementsByTagName("responses")[0]; var lastUpdate=elDocRoot.attributes.getNamedItem("updateTime"); if (parseInt(lastUpdate)>this.lastUpdateTime){ this.lastUpdateTime=lastUpdate; e Updated timestamp } if (elDocRoot){ for(i=0;i if (elChild.nodeName=="command"){ var attrs=elChild.attributes; var id=attrs.getNamedItem("id").value; var command=net.commandQueue.sent[id]; if (command){ command.parseResponse(elChild); } }else if (elChild.nodeName=="update"){ if (this.implementsFunc("onUpdate")){ this.onUpdate.call(this,elChild); f Updated handler } } Licensed to jonathan zheng 220 CHAPTER 6 The user experience } } } net.CommandQueue.prototype.repeat=function(freq){ g Server poller this.unrepeat(); if (freq>0){ this.freq=freq; var cmd="net.cmdQueues["+this.id+"].fireRequest()"; this.repeater=setInterval(cmd,freq*1000); } } net.CommandQueue.prototype.unrepeat=function(){ h Polling switch if (this.repeater){ clearInterval(this.repeater); } this.repeater=null; } We’ve added quite a bit of new functionality here. Let’s step through it. First, we’ve introduced a global lookup of command queue objects b. This is a necessary evil given the limitations of the setInterval() method, which we’ll discuss shortly. The constructor takes a unique ID as an argument and registers itself with this lookup under this key. The CommandQueue constructor now takes two other new arguments c. onUpdate is a Function object that is used to handle the