DOM functions v.s. innerHTML v.s. cloneNode
JavascriptでDOM要素を生成するにはいろいろなやり方があるけど,どれが一番速いのか気になっていた。漠然と,cloneNode速そうだなーと思ってそれを使っていた。
思い込みで速度を語るのはよくない!と思ったので,Firefox3 RC1 + Firebug 1.2.0b1 で軽くベンチマークを取ってみた。
ベンチマークに利用したソースと,結果を貼り付けてみる。
シンプルなHTMLを生成した場合
<div><a href="http://example.com">Example</a></div>
こんなHTMLを,
- document.createElement, document.createTextNode, elem.appendChild を使って生成した場合
- div を生成して innerHTML に内容を代入する場合
- あらかじめ生成してある要素を cloneNode(true) してコピーする場合
の3つの方法で生成した場合の速度を測定してみた。
Javascriptソース
var simple_elem = document.createElement('div'); simple_elem.innerHTML = '<a href="http://example.com/">Example</a>'; function simple_DOM() { var div = document.createElement('div'); var a = document.createElement('a'); a.appendChild(document.createTextNode('Example')); div.appendChild(a); } function simple_innerHTML() { var div = document.createElement('div'); div.innerHTML = '<a href="http://example.com/">Example</a>'; } function simple_cloneNode() { var div = simple_elem.cloneNode(true); } const n = 10000; console.profile(); for(var i = 0; i < n; i++) simple_innerHTML(); for(var i = 0; i < n; i++) simple_DOM(); for(var i = 0; i < n; i++) simple_cloneNode(); console.profileEnd();
結果
Function | Calls | Percent | Own Time | Time | Avg | Min | Max |
---|---|---|---|---|---|---|---|
simple_DOM | 10000 | 36.15% | 384.087ms | 384.087ms | 0.038ms | 0.034ms | 2.134ms |
simple_innerHTML | 10000 | 49.02% | 520.853ms | 520.853ms | 0.052ms | 0.048ms | 1.514ms |
simple_cloneNode | 10000 | 14.83% | 157.589ms | 157.589ms | 0.016ms | 0.013ms | 2.876ms |
(?)() | 6 | 0% | 0.051ms | 0.051ms | 0.008ms | 0.005ms | 0.022ms |
複雑なHTMLを生成した場合
<table> <tbody> <tr><th>aaa</th><td>hoge</td></tr> <tr><th>bbb</th><td>hoge</td></tr> </tbody> </table>
こんなHTMLを先ほどと同じやり方で生成してみた。
Javascriptソース
var complex_elem = document.createElement('table'); complex_elem.innerHTML = '<tbody><tr><th>aaa</th><td>hoge</td></tr><tr><th>bbb</th><td>hoge</td></tr></tbody>'; function complex_DOM() { var table = document.createElement('table'); var tr_a = document.createElement('tr'); var th_a = document.createElement('th'); th_a.appendChild(document.createTextNode('aaa')); tr_a.appendChild(th_a); var td_a = document.createElement('td'); td_a.appendChild(document.createTextNode('hoge')); tr_a.appendChild(td_a); var tr_b = document.createElement('tr'); var th_b = document.createElement('th'); th_b.appendChild(document.createTextNode('bbb')); var td_b = document.createElement('td'); td_b.appendChild(document.createTextNode('hoge')); tr_b.appendChild(th_b); tr_b.appendChild(td_b); table.appendChild(tr_a); table.appendChild(tr_b); } function complex_innerHTML() { var table = document.createElement('table'); table.innerHTML = '<tbody><tr><th>aaa</th><td>hoge</td></tr><tr><th>bbb</th><td>hoge</td></tr></tbody>'; } function complex_cloneNode() { var table = complex_elem.cloneNode(true); } const n = 10000; console.profile(); for(var i = 0; i < n; i++) complex_innerHTML(); for(var i = 0; i < n; i++) complex_DOM(); for(var i = 0; i < n; i++) complex_cloneNode(); console.profileEnd();
結果
Function | Calls | Percent | Own Time | Time | Avg | Min | Max |
---|---|---|---|---|---|---|---|
complex_DOM | 10000 | 57.84% | 1467.06ms | 1467.06ms | 0.147ms | 0.129ms | 20.188ms |
complex_innerHTML | 10000 | 30.62% | 776.493ms | 776.493ms | 0.078ms | 0.068ms | 6.842ms |
complex_cloneNode | 10000 | 11.54% | 292.589ms | 292.589ms | 0.029ms | 0.019ms | 47.847ms |
(?)() | 6 | 0% | 0.05ms | 0.05ms | 0.008ms | 0.004ms | 0.022ms |
考察
結果としては,予想通り。cloneNodeが速かった。DOM関数を使う場合には関数呼び出しのオーバーヘッドがあるだろうし,innerHTMlにはHTMLのパースをする分だけ時間がかかることを考えれば,まあ当然な結果だろう。ソースの長さを見る限り,DOM関数は遅くなっても当たり前,という感じすらする。
まとめ
似たような要素をたくさん生成するときはcloneNode使うのがいいよ。
とはいえ,全く同じ要素をたくさん生成することはまれだろう。次回は,内容が微妙に異なる,似たような要素をたくさん生成する場合にどうなるかを実験してみたい。