Re: RemoveChild and IE crash !

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance




"Randy Webb" <HikksNotAtHome@xxxxxxx> wrote in message
news:2a-dnbSHTMM39vrZRVn-sQ@xxxxxxxxxxxxxx
Anthony Jones said the following on 5/12/2006 3:08 PM:
"Randy Webb" <HikksNotAtHome@xxxxxxx> wrote in message
news:qvKdnYFq4sU5IfnZRVn-jg@xxxxxxxxxxxxxx
Anthony Jones said the following on 5/12/2006 3:03 AM:
"abcd" <abcd@xxxxxxxx> wrote in message
news:OlVEbb7cGHA.4576@xxxxxxxxxxxxxxxxxxxxxxx
function RemoveField(field)
{
var element = document.getElementById(field);
element.parentNode.removeChild(element);
}


I am calling this function many times in my DHTMl page. field is
always
a
TBODY. TBODY contains one row with 2 cells. Basically I wish to
remove
TBODY
and hence the controls in that.

this works well....but at some point I get IE crash ....whats the
efficient
way to removing the fields....


thanks

You would be better off enumerating the the rows and removing them
Perhaps.


'Perhaps'?? What do you mean?

Perhaps enumerating the rows would be better, perhaps it wouldn't.
Simple remove the TBODY if you want to remove everything in it.


Ok that makes sense now.

Is there an alternative that is better?
Is there' a problem or caveat to keep in mind?

If there are 100 rows in the TBODY then enumerating them and removing
them one at a time wouldn't seem like the best way if you simply remove
the TBODY - and all it's children - in one line.


Agreed

or better yet assigning HTML of the whole table to the innerHTML
property
of the element containing the table.
To remove the table, yes. But to remove parts of the table, no.


Perhaps. It depends on how many rows you need to remove.

No, it doesn't. If you want to remove all the rows in a TBODY, then you
remove the TBODY - and recreate it if you need it.


Well it's the recreate bit that's the problem. Removing the tbody isn't a
problem but the real issue is what you do if you need to recreate and
re-populate it.


Manipulating the DOM in script is can be very slow so there comes a
point where building what you want as a string and assigning to an
innerHTML property makes a signficant difference to how the UI
responds to the user.

I would like to see a sample page that shows that innerHTML will beat
DOM methods when manipulating tables - with regards to constructing it.

Before you construct a sample, have a look at this article:
<URL:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndude/html/dude100499.asp>

Where it shows - undeniably - that innerHTML is very expensive
(memory-wise) and slower than what MS refers to as the TOM - Table
Object Model.


Well let's first remember that this article was written in 1999 and tested
against IE5.

This is the best DHTML effort from this article:-

<html>
<title>Test DTHML</title>
<body onload="init()">
<script defer>
function init() {
var tbl, tbody, tr, td, text, i, max;
max = 30000;
var theDoc = document;
var theBody = theDoc.body;

tbl = theDoc.createElement("TABLE");
tbl.style.tableLayout = "fixed";
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.appendChild(tbody);
theBody.appendChild(tbl);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
tbody.appendChild(tr);
td = theDoc.createElement("TD");
tr.appendChild(td);
td.innerText = "Text";
}
}
</script>
</body>
</html>

I've changed insertBefore in the article to appendChild (it didn't change
the timing). I've also increased the max count from 1000 to 30000 so any
appreciable difference can be seen on modern(ish) hardware (I'm using 1.7GHz
P4).

Curiously Mr Wallent did not include the innerHTML sample that didn't
perform very well. Here's mine:-

<html>
<title>Test InnerHTML</title>
<body onload="init()">
<script defer>
function init()
{
var i, max;
max = 30000;

var asTable = new Array(max+2)
asTable[0] = '<table border="1" style="table-layout:fixed"><tbody>'
for (i=1; i <= max; i++)
asTable[i] = "<tr><td>Text</td></tr>"
asTable[max+1] = "</tbody></table>"

document.body.innerHTML = asTable.join("\n")

}
</script>
</body>
</html>


In IE6 this InnerHTML version significantly out performs the first DHTML
sample.

In FF I had to change the innerText to innerHTML for assigning the text
content to the TD. This made no difference in the IE6 performance.
Surprisingly I couldn't get the first sample to complete in FF (1.5.0.3) at
all. In 10 seconds it had created 4096 rows, in 60 seconds it creates
16384. I suspect that this an exponential slow down as individual items get
added to the DOM. It managed the second sample in a few seconds just a
little quicker than IE6.

So I tweaked this test into something a little closer to reality. A 3000
row table with 10 columns:-

<html>
<title>Test DHTML</title>
<body onload="init()">
<script defer>
function init() {
var tbl, tbody, tr, td, text, i, j, maxRows, maxCols;
maxRows = 3000;
maxCols = 10;
var theDoc = document;
var theBody = theDoc.body;

tbl = theDoc.createElement("TABLE");
tbl.style.tableLayout = "fixed";
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.appendChild(tbody);
theBody.appendChild(tbl);
for (i=0; i<maxRows; i++) {
tr = theDoc.createElement("TR");
tbody.appendChild(tr);
for (j=0; j<maxCols; j++) {
td = theDoc.createElement("TD");
tr.appendChild(td);
td.innerHTML = "Text" + (i * maxCols + j).toString();
}
}
}
</script>
</body>
</html>

Now this does actually finish but takes the best part of a minute in FF
whereas IE6 it is somewhat quicker but still took about 30 seconds.

Here's my innerHTML version of the above:-

<html>
<title>Test 5</title>
<body onload="init()">
<script defer>
function init()
{

var maxRows = 3000;
var maxCols = 10;
var asRow = new Array(maxCols)

var asTable = new Array(maxRows+2)
asTable[0] = '<table border="1" style="table-layout:fixed"><tbody>'
for (var i=1; i <= maxRows; i++)
{
for (var j=0; j<maxCols; j++)
{
asRow[j] = "<td>Text" + ((i - 1) * maxCols + j).toString() + "</td>"
}
asTable[i] = "<tr>" + asRow.join("") + "</tr>"

}
asTable[maxRows+1] = "</tbody></table>"

document.body.innerHTML = asTable.join("\n")

}
</script>
</body>
</html>


Both IE6 and FF only take 4 seconds to render this. Clear far from being
'undeniably..very expensive' InnerHTML is quite the opposite.

So why is innerHTML so much quicker then using DHTML?

Put simply innerHTML can defer the layout calculations until after the DOM
is complete whereas each modification to the DOM made by code in the DHTML
samples require some layout calculations to happen after each call to the
DOM.

In the real world we may not have as many rows but the HTML contents of the
TD may be more complex as well as various properties and styles of the
elements being created will need modifying. Each such change to the DOM
incurs an overhead.

After having done this sort of testing on real world apps where DHTML was
not providing acceptable performance I've used the innerHTML approach. This
includes the situations similar to the case in point. Destroying the entire
table and assigning a new version of it to an innerHTML property was proving
significantly faster than dropping parts of the table and create elements
via DHTML.

An approach I find particularly effective is to use an XML DOM to create the
html elements then assign the xml content to an innerHTML property when the
DOM is complete. This allows the code to remain readable and well
structured (no nasty string concats etc) whilst remaining reasonable
performant.

This last sample demonstrates this. FF is still a little disappointing ~12
Secs, IE6 significantly outperforms it in this version at ~6 Secs.


<html>
<title>Test XML</title>
<body onload="init()">
<script defer>

isIE = navigator.userAgent.indexOf('MSIE') > 0 //Not good, but good enough
here

if (!isIE)
{
Node.prototype.__defineGetter__("xml", _moz_Node_getXML)
}

function _moz_Node_getXML()
{
return (new XMLSerializer()).serializeToString(this)
}


function init()
{
var maxRows = 3000;
var maxCols = 10;
var oDOM = getDOM()

var tbl = oDOM.appendChild(oDOM.createElement("table"));
tbl.setAttribute("style", "table-layout:fixed")
tbl.setAttribute("border", "1")

var tbody = addXMLElem(tbl, "tbody")
for (var i=0; i<maxRows; i++)
{
var tr = addXMLElem(tbody, "tr");

for (j=0; j<maxCols; j++)
addXMLElem(tr, "td", "Text" + (i * maxCols + j).toString())
}
document.body.innerHTML = tbl.xml
}

function addXMLElem(parent, name, value)
{
var oDOM = parent.ownerDocument
var oElem = oDOM.createElement(name)
parent.appendChild(oElem)
if (value != null)
{
if (isIE)
oElem.text = value
else
oElem.appendChild(oDOM.createTextNode(value))
}
return oElem
}


function getDOM()
{
if (isIE)
return new ActiveXObject("MSXML2.DOMDocument.3.0")
else
return document.implementation.createDocument("", "", null)
}


</script>
</body>
</html>


Anthony.




.



Relevant Pages

  • Re: extending a select list
    ... var old = document.getElementById; ... so what you really want is a faster method than new Option? ... because Opera is too slow and if you use innerHTML I'll bet some other ...
    (comp.lang.javascript)
  • Re: Javascript Library
    ... inserting them in a container element via innerHTML and then proclaiming ... All in the name of having an "Ajax site." ... var el = document.getElementById; ... I tested for a script element at the head of the fragment and added ...
    (comp.lang.javascript)
  • Re: RTL and offsetLeft in IE 6
    ... Ironically, I used innerHTML to simplify things; Apparently, its non-standard nature makes things only worse. ... var body = document.body, ... I just looked at "My Library" again and noticed an inconsistency in testing for exactly this property - firstChild. ... but its counterpart that follows next - `setElementText` goes straight ahead and uses `firstChild` in a second branch without a test similar to the one in `getElementText`. ...
    (comp.lang.javascript)
  • Re: UL LI get text
    ... Certainly the innerHTML ... if (typeof el.textContent == 'string') return el.textContent; ... var x = el.childNodes; ...
    (comp.lang.javascript)
  • Re: problem in line: var theRow = table.createElement("tr")
    ... I am learning JavaScript. ... var visibility = [ ... can use innerHTML to create an entire table or the content of a cell. ...
    (comp.lang.javascript)