AJAX In Action [155]
Licensed to jonathan zheng 316 CHAPTER 8 Performance Figure 8.9 The Drip tool allows detailed queries on the internal state of Internet Explorer’s DOM tree. So far, we’ve looked at individual patterns and idioms for handling performance issues in small sections of code. When we write an Ajax application of even moderate size, the various patterns and idioms in each subsystem can interact with each other in surprising ways. The following section describes a case study that illustrates the importance of understanding how patterns combine with one another. 8.4.2 A simple example In our discussion thus far, we have covered the theory of memory management and described a few patterns that might help us when programmatically creating interface elements. In a real-world Ajax application, we will employ several patterns, which will interact with one another. Individual patterns have impacts on performance, but so do the interactions between patterns. It is here that having access to a common vocabulary to describe what your code is doing becomes very valuable. The best way to illustrate this principle is by example, so in this section we introduce a simple one and present the performance impact of varying the combination of patterns that it uses. In the simple test program, we can repeatedly create and destroy small ClickBox widgets, so called because they are little boxes that the user can click on with Licensed to jonathan zheng Designing for performance 317 the mouse. The widgets themselves have a limited behavior, described by the following code: function ClickBox(container){ this.x=5+Math.floor(Math.random()*370); this.y=5+Math.floor(Math.random()*370); this.id="box"+container.boxes.length; this.state=0; this.render(); container.add(this); } ClickBox.prototype.render=function(){ this.body=null; if (this.body==null){ this.body=document.createElement("div"); this.body.id=this.id; } this.body.className='box1'; this.body.style.left=this.x+"px"; this.body.style.top=this.y+"px"; this.body.onclick=function(){ var clickbox=this.backingObj; clickbox.incrementState(); } } ClickBox.prototype.incrementState=function(){ if (this.state==0){ this.body.className='box2'; }else if (this.state==1){ this.hide(); } this.state++; } ClickBox.prototype.hide=function(){ var bod=this.body; bod.className='box3'; } When first rendered, the ClickBoxes are red in appearance. Click on them once, and they turn blue. A second click removes them from view. This behavior is implemented by creating two-way references between the domain model object and the DOM element that represents it onscreen, as discussed earlier. Programmatically, each ClickBox consists of a unique ID, a position, a record of its internal state (that is, how many clicks it has received), and a body. The body Licensed to jonathan zheng 318 CHAPTER 8 Performance is a DOM node of type DIV. The DOM node retains a reference to the backing object in a variable called backingObj. A Container class is also defined that houses ClickBox objects and maintains an array of them, as well as a unique ID of its own: function Container(id){ this.id=id; this.body=document.getElementById(id); this.boxes=new Array(); } Container.prototype.add=function(box){ this.boxes[this.boxes.length]=box; this.body.appendChild(box.body); } Container.prototype.clear=function(){ for(var i=0;i } this.boxes=new Array(); report("clear"); newDOMs=0; reusedDOMs=0; } A screenshot of the application is shown in figure 8.10. Figure 8.10 Our memory management demo application, after creation of the first 100 widgets. The user has just clicked one of the widgets with the mouse. Licensed to jonathan zheng Designing for