AJAX In Action [152]
var box=document.createElement("div");
box.id="messagebox";
box.classname="messagebox";
var txtNode=document.createTextNode(txt);
box.appendChild(txtNode);
setTimeout("removeBox('messagebox')",timeout);
}
function removeBox(id){
var box=document.getElementById(id);
if (box){
box.style.display='none';
}
}
Licensed to jonathan zheng JavaScript memory footprint 309 When we call Message(), a visible message box is created, and a JavaScript timer is set to call another function that removes the message after a given time. The variables box and txtNode are both created locally and go out of scope as soon as the function Message() has exited, but the document nodes that are created will still be reachable, because they have been attached to the DOM tree. The removeBox() function handles the job of making the created DOM node go away when we're done with it. We have several possible options for doing this, from a technical standpoint. In the example above, we removed the box simply by hiding it from view. It will still occupy memory when invisible, but if we are planning on redisplaying it soon, that won’t be a problem. Alternatively, we could alter our remove() method to dislocate the DOM nodes from the main document and hope that the garbage collector spots them before too long. Again, though, we don’t actually destroy the variable, and the duration of its stay in memory is outside our control. function removeBox(id){ var box=document.getElementById(id); if (box && box.parentNode){ box.parentNode.removeChild(box); } } We can discern two patterns for GUI element removal here, which we will refer to as Remove By Hiding and Remove By Detachment. The Message object here has no event handlers—it simply appears and disappears at its own speed. If we link the domain model and DOM nodes in both directions, as we did for our Button object, we would need to explicitly invoke the cleanUp() function if we were using a Remove By Detachment pattern. Both approaches have their advantages and disadvantages. The main deciding factor for us is to ask whether we are going to reuse the DOM node at a later date. In the case of a general-purpose message box the answer is probably “yes,” and we would opt for removal by hiding. In the case of a more specific use, such as a node in a complex tree widget, it is usually simpler to destroy the node when finished with it than to try to keep lots of references to dormant nodes. If we choose to use Remove By Hiding, we can adopt a complementary approach of reusing DOM nodes. Here, we modify the message-creation function to first check for an existing node and create a new one only if necessary. We could rewrite our Message object constructor to accommodate this: function Message(txt, timeout){ var box=document.geElementById("messagebox"); var txtNode=document.createTextNode(txt); Licensed to jonathan zheng 310 CHAPTER 8 Performance if (box==null){ box=document.createElement("div"); box.id="messagebox"; box.classname="messagebox"; box.style.display='block'; box.appendChild(txtNode); }else{ var oldTxtNode=box.firstChild; box.replaceChild(txtNode,oldTxtNode); } setTimeout("removeBox('messagebox')",timeout); } We can now contrast two patterns for GUI element creation, which we will refer to as Create Always