Dynamic tables approach

  • Thread starter Anthony Levensalor
  • Start date
A

Anthony Levensalor

Evening, gents!

I've got two different methods for adding tables to the dom, and curious
as to which approach might be better, and why. If anyone has the time
and/or the inclination to reply, thanks in advance.

Method 1:


var table = document.createElement("table")
var tbody = document.createElement("tbody")

var hRow = document.createElement("tr")
var cells = [];
var cells[0] =
[
document.createElement("td"),
document.createElement("td"),
document.createElement("td")
]

for (var i = 0; i < cells[0].length; ++i) {
hRow.appendChild(cells[0])
}

tbody.appendChild(hRow)
table.appendChild(tbody)

someParentElement.appendChild(table)


Method 2:

var table = document.createElement("table")
var hRow = table.insertRow(-1)

var cells = []
var cells[0] =
[
hRow.insertCell(0),
hRow.insertCell(1),
hRow.insertCell(2)
]

someParentElement.appendChild(table)


I checked out the ECMA Script Language Binding index
(http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html),
and I can't see anything necessarily good or bad about one way or the
other, save for the fact that Method 1 above has a lot more typing.

I've used both, started out with #1 some time back and went to #2 when I
found out it was available, is there some reason you guys think one is
any better than the other?

All the best,
~A!
 
A

Anthony Levensalor

-Lost said:
<snip>

Make a hammer, make a nail, then use them on the wood.


<snip>

Use the available hammer and nail on the wood.

I've not seen many instances where the DOM interface is going to be
slower (and more verbose) than dynamically creating each element.

Actually, it's the faster of the two in the tests I ran.

"Method 2" runs faster in my scenario on several browsers.

Can you provide the scenario(s)? Perhaps something I am missing here.

[snip]
My brain likes to play tricks on me sometimes, but that seems fairly
obvious.

And it seemed obvious to me, as well. Here is the data from the tests I ran:

(Results are averaged over one hundred runs)
**NOTE: I counted appending to the body element in the calculations.

100 rows, 5 cells each, 1 text node (4 character string) appended to
each cell:


Method 1 Method 2
IE 129.3ms 236.5ms
FF 53.5ms 38.3ms
Saf 31.8ms 24.5ms

1000 rows, 5 cells each, 1 text node (4 character string) appended to
each cell

Method 1 Method 2
IE 1,043ms 27,152ms
FF 518ms 537ms
Saf 189ms 808ms


Firefox had the most consistent results, only deviating slightly based
on the method used.

Safari surprised me with how lightning fast it was on the smaller tables
and on the direct manipulation method. It started to choke on the second
method at a thousand rows, but my curiosity is sated on this one.

IE, of course, puked all over itself, peed it's pants, and ran home to
hide under the bed. I was not surprised that one of the two methods
would cause it to jump so much, but I was surprised at which one.

It retrospect, I don't know why the results surprised me. It makes a lot
of sense to me that direct DOM manipulation is going to be faster, and I
definitely have a reason to do it that way now, so I guess I'll just
implement some nice happy table management functions and use the DOM.


Here is the code for the Method 1 test:
/********************************************/
var numRows = 1000;
var cellsPerRow = 5;
var m1TimeStart = new Date()

var table1 = document.createElement("table")
var tbody = document.createElement("tbody")

for (var i = 0; i < numRows; ++i) {
var crow = document.createElement("tr")
for (var j = 0; j < cellsPerRow; ++j) {
var td = document.createElement("td")
td.appendChild(document.createTextNode(i + ", " + j))
crow.appendChild(td)
}
tbody.appendChild(crow)
}

table1.appendChild(tbody)
document.body.appendChild(table1)

var time1 = new Date() - m1TimeStart
/*************************************************************/

And for the second method:

/************************************************************/
var numRows = 1000;
var cellsPerRow = 5;
var m2TimeStart = new Date()


var table2 = document.createElement("table")

for (var i = 0; i < numRows; ++i) {
var crow = table2.insertRow(-1)
for (var j = 0; j < cellsPerRow; ++j) {
var td = crow.insertCell(j)
td.appendChild(document.createTextNode(i + ", " + j))
}
}

document.body.appendChild(table2)

var time2 = new Date() - m2TimeStart
/**************************************************************/


All the best,

~A!
 
A

AKS

I've used both, started out with #1 some time back and went to #2 when I
found out it was available, ...

There is a way #3 (fastest):

var numRows = 1000;
var cellsPerRow = 5;
var m3TimeStart = new Date;

var wrapper = document.createElement("div");
var table = '<table>';

for (var i = 0; i < numRows; ++i) {
table += '<tr>'
for (var j = 0; j < cellsPerRow; ++j) {
table += '<td>' + i + ', ' + j + '</td>';
};
table += '</tr>';
};

wrapper.innerHTML = table + '</table>';
document.body.appendChild(wrapper.firstChild);

var time3 = new Date - m3TimeStart;
 
A

Arnaud Diederen

AKS said:
There is a way #3 (fastest):

var numRows = 1000;
var cellsPerRow = 5;
var m3TimeStart = new Date;

var wrapper = document.createElement("div");
var table = '<table>';

for (var i = 0; i < numRows; ++i) {
table += '<tr>'
for (var j = 0; j < cellsPerRow; ++j) {
table += '<td>' + i + ', ' + j + '</td>';
};
table += '</tr>';
};

wrapper.innerHTML = table + '</table>';
document.body.appendChild(wrapper.firstChild);

var time3 = new Date - m3TimeStart;


Hi,

If I'm not mistaken, that could be even faster by avoiding string
concatenation (untested):

var numRows = 1000;
var cellsPerRow = 5;
var m4TimeStart = new Date;

var wrapper = document.createElement("div");
var parts = ['<table>', '<tbody>'];

for (var i = 0; i < numRows; ++i) {

parts.push ('<tr>');

for (var j = 0; j < cellsPerRow; ++j) {

parts.push ('<td>', i, ', ', j, '</td>');
};

parts.push ('</tr>');
};

parts.push ('</tbody>', '</table>');

wrapper.innerHTML = parts.join ("");
document.body.appendChild(wrapper.firstChild);

var time4 = new Date - m4TimeStart;
 
A

Anthony Levensalor

AKS said:
There is a way #3 (fastest):

var numRows = 1000;
var cellsPerRow = 5;
var m3TimeStart = new Date;

var wrapper = document.createElement("div");
var table = '<table>';

for (var i = 0; i < numRows; ++i) {
table += '<tr>'
for (var j = 0; j < cellsPerRow; ++j) {
table += '<td>' + i + ', ' + j + '</td>';
};
table += '</tr>';
};

wrapper.innerHTML = table + '</table>';
document.body.appendChild(wrapper.firstChild);

var time3 = new Date - m3TimeStart;

I'm not an innerHTML kinda guy, truthfully. I have some issues with
innerHTML, namely:

-Unreadable code, hence harder for me to maintain

-It's a proprietary property. It's not part of the W3C DOM, so I don't
trust it all that much, regardless of the wide-spread support it now enjoys.

-InnerHTML doesn't care if your markup is valid or not. It just jams a
string into a spot for you, which makes creating valid elements (thanks
to typos and my not-so-nimble fingers) an issue. Debugging my DOM
methods is simplicity in itself, not so with innerHTML.

-It's unstructured enough to make me feel icky writing it. I'm
disappointed that anyone other than IE ever supported it, and
disappointed IE came up with it, but I'm used to that feeling.

But enough about innerHTML. Thanks for the feedback, and the benchmarks
do prove you out on the speed issue. For me, it's not a viable third
option, but it may very well be to a lot of others.

All the best,
~A!
 
A

AKS

If I'm not mistaken, that could be even faster by avoiding string
concatenation ...

Yes, in IE. Quick test (approximate results):
string concatenation: IE - 391ms Opera 9 - 63ms FF 1.5 - 203ms;
array join: IE - 219ms Opera 9 - 78ms FF 1.5 - 234ms.
 
A

Anthony Levensalor

AKS said:
Support of this property will be wider (sooner or later), and you will
have to trust it much more (also sooner or later) ;).

And once they standardize it, my friend, I will absolutely have to trust
it more.

Keep in mind, though, that once they standardize the behavior to use the
logic in that first link, IE will make it niiiiice and slow, and the
whole discussion will be moot. ;)

Have a look at the algorithms they want to standardize, brother. IE
_will_ find a way to screw that up for us, I guarantee. :)


~A!
 
S

SAM

AKS a écrit :
There is a way #3 (fastest):

: Way #3 : Way #2 : Way #1 :
- IE (5.2.3 Mac) : 32,714 : error : 157,841 :
- Fx (2.0.0.11) : 93 : 349 : 422 :
- Safari (2.0.4) : 60 : 133 : 129 :
- Opera (9.0.0) : 48 : 579 : 550 :

iMac 2.16Ghz Intel Core 2 duo - syst 10.4.10
 
S

SAM

Arnaud Diederen (aundro) a écrit :
If I'm not mistaken, that could be even faster by avoiding string
concatenation (untested):

: Way #1 : Way #2 : Way #3 : join() :
- IE (5.2.3 Mac) : 157,841 : error : 32,714 : error :
- Fx (2.0.0.11) : 422 : 349 : 93 : 116 :
- Safari (2.0.4) : 129 : 133 : 60 : 60 :
- Opera (9.0.0) : 550 : 579 : 48 : 63 :

iMac 2.16Ghz Intel Core 2 duo - syst 10.4.10
 
A

Anthony Levensalor

SAM said:
: Way #3 : Way #2 : Way #1 :
- IE (5.2.3 Mac) : 32,714 : error : 157,841 :
- Fx (2.0.0.11) : 93 : 349 : 422 :
- Safari (2.0.4) : 60 : 133 : 129 :
- Opera (9.0.0) : 48 : 579 : 550 :

iMac 2.16Ghz Intel Core 2 duo - syst 10.4.10

Thanks Sam! I suppose I probably ought to be supporting IE5 on the Mac a
little better than that, wouldn't you say? :)

~A!
 
S

SAM

Anthony Levensalor a écrit :
SAM said:

Thanks Sam! I suppose I probably ought to be supporting IE5 on the Mac a
little better than that, wouldn't you say? :)

No, in surprising way, it is the innerHTML which seems to be the fastest
and better supported.

I don't know about IE Win (I think is is too) but IE Mac is very very
lazy with creation of tables or when acting on then (what could be the
way, create, clone ...)

It's not very important ... this IE is no longer very much used.
 
A

Anthony Levensalor

SAM said:
Anthony Levensalor a écrit :

No, in surprising way, it is the innerHTML which seems to be the fastest
and better supported.

Yes, it definitely does seem to be enjoy the best speed and support of
the bunch. At least now I know what was hanging IE7 for the last two
days of testing, so there is *that* at least. :)

I don't know about IE Win (I think is is too) but IE Mac is very very
lazy with creation of tables or when acting on then (what could be the
way, create, clone ...)

Actually, I've had a lot of luck with IE when I designate a function
"pointer" and then repeatedly call it. I watched it via task manager
this morning, and it was a little surprising.

When I do something like:

var row;
for (var i = 0; i < 1000; ++i) {
row = document.createElement("tr");
}

It starts to leak memory on me. But when I do:

var createFunc = document.createElement;
var row;
for (var i = 0; i < 1000; ++i) {
row = createFunc('tr');
}

It doesn't seem to leak on the thousand iterations at all, although I'm
sure it would after a bit. It also _appears_ to go faster, but I haven't
benchmarked, so I can't stick my neck out on that one. It makes sense
that it would go a little faster, not doing the lookup in the engine for
the function pointer or reference every single time, though.

I'll need to test some more.

~A!
 
N

nolo contendere

Arnaud Diederen (aundro) a écrit :



                  :  Way #1 : Way #2 :  Way #3 : join() :
- IE (5.2.3 Mac) : 157,841 : error  : 32,714  : error  :
- Fx (2.0.0.11)  :     422 :   349  :     93  :   116  :
- Safari (2.0.4) :     129 :   133  :     60  :    60  :
- Opera (9.0.0)  :     550 :   579  :     48  :    63  :

iMac 2.16Ghz Intel Core 2 duo - syst 10.4.10

Could you post results for Safari 3.0.4 and FF 3.0b2 as well?
 
A

Anthony Levensalor

nolo contendere said:
Could you post results for Safari 3.0.4 and FF 3.0b2 as well?

If you're running the browsers, pitch in, dude! Grab the tests from the
thread and give them a run, join in the festivities.

~A!
 
N

nolo contendere

nolo contendere said:





If you're running the browsers, pitch in, dude! Grab the tests from the
thread and give them a run, join in the festivities.
Way #2 Way #3 join
FF 3.0b2 432 143 172
Safari 3.0.2 156 47 63

on a Core Duo 2.00GHz laptop 1 GB RAM IBM Thinkpad T60
 
A

Anthony Levensalor

nolo contendere said:
Way #2 Way #3 join
FF 3.0b2 432 143 172
Safari 3.0.2 156 47 63

on a Core Duo 2.00GHz laptop 1 GB RAM IBM Thinkpad T60

I really should go get that beta of FF. I'm just too happy having stable
stuff at the moment. :)
 
N

nolo contendere

nolo contendere said:



I really should go get that beta of FF. I'm just too happy having stable
stuff at the moment. :)

My main gripe about the beta is that plugins aren't ready for it yet.
I'm not one who uses many, but it would be nice if I could get Firebug.
 
A

Anthony Levensalor

*** nolo contendere *** wrote a whole bunch of nifty stuff On 1/9/2008
11:30 AM:
[snip]
My main gripe about the beta is that plugins aren't ready for it yet.
I'm not one who uses many, but it would be nice if I could get Firebug.

You know what would be a great learning experience? If we went ahead and
updated it for the 3 beta. Probably be a lot of fun, too.

~A!
 
P

pr

Anthony said:
Here is the code for the Method 1 test:
[...]
.... and with a small amount of tweaking it can be made to outperform the
other methods in most cases:

var numRows = 1000;
var cellsPerRow = 5;
var m5TimeStart = new Date()

var table1 = document.createElement("table")
var tbody = document.createElement("tbody")
var crow = document.createElement("tr")
var j, td, tx = [];
for (j = 0; j < cellsPerRow; ++j) {
td = document.createElement("td")
tx.push(td.appendChild(document.createTextNode("-")))
crow.appendChild(td)
}

for (var i = 0; i < numRows; ++i) {
for (j = 0; j < cellsPerRow; ++j) {
tx[j].nodeValue = i + ", " + j
}
tbody.appendChild(crow.cloneNode(true))
}

table1.appendChild(tbody)
document.body.appendChild(table1)

var time5 = new Date() - m5TimeStart
/*************************************************************/

Tests on an old AMD Athlon 1.2 running (mostly) Linux:

#1 #2 #3 #4 #5
Opera 9.25 474 539 165 208 101
Firefox 2.0.0.11 1176 1231 401 459 378
Konqueror 3.5.5 747 2422 3494 457 325

IE 6 (win) 1769 81737 1696 594 698
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,190
Latest member
Martindap

Latest Threads

Top