<< Prev Page Next Page >>

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


DOM API と innerHTML のパフォーマンス比較

404 Blog Not Found:javascript - element.innerHTML はなぜ速く見えるかにて

InnerHTMLは速くない。速く見えるだけだ。
とあった。Danさんの予測は、DOM APIが遅く見えるのは、DOM Treeを更新していくたびに再描画が走るからではないかというもの。
そうなのかなと思って実験を作ってみました。
  • 複雑なHTMLを文字列として作ってからinnerHTMLに代入するのと、
  • 再描画が一度も走らないよう、あらかじめ複雑なElementを作ってから最後にdocumentにくっつけるようにするの
  • Elementを作ったそばからどんどんdocumentにくっつけていくの
で比較しました。↓以下実験。




innerHTML DOM1 DOM2

やっぱり速いんじゃないかなinnerHTML。WindowsのFirefoxとIE6ではinnerHTMLが大差で速いです。おそらくJavaScriptエンジンが一行一行複雑なオブジェクトメソッドを操作しなきゃなんないDOM APIよりも、ブラウザのネイティブコード中でも最もゴリゴリに最適化された部分であろう「HTML文字列をparseして表示する」っていうタスクを叩くinnerHTMLのほうが速いっていうことじゃないでしょうか。

ついでに、大きなElementを作って最後にbodyに接続するのと、createElement()したそばからbodyに接続していくのの比較は想像通り、最後にbodyに接続したほうが速い。Firefox のソースコードは見たこと無いけど、Java の AWT とか swing のソースコードをめちゃめちゃ真剣に解析して似たようなものを独自に作ったことがあるのでまあ納得できる。DOMツリーに変更を加えると再描画範囲を決定するために親をたどりながら「この範囲内は再描画必要ですよ」とフラグを立てていくみたいなことをしてるんだろう。基本的な考え方はそう遠くないはず。

と、Firefoxでだけ試して書いてたら、IEでは「DOM2」のほうが速いじゃん。IEで再帰呼び出しが遅くなるパターンに何かはまっちゃったのかも。いやーん

あと、Operaがなんだか速い。傾向はFirefoxと同じかな。

↓以下ソース。


var ROWS = 5; var COLS = 2; var DEPTH = 2; /** * 複雑なElementをつくって最後にbodyにつなげる */ function createComplexDOM(area) { function createInner(elem, depth) { var table = document.createElement("TABLE"); table.border = 1; table.cellSpacing = 0; table.cellPadding = 2; var tbody = document.createElement("TBODY"); for (var i = 0; i < ROWS; i++) { var tr = document.createElement("TR"); for (var j = 0; j < COLS; j++) { var td = document.createElement("TD"); if (depth > 0) { createInner(td, depth - 1); } else { var text = document.createTextNode('DOM (' + i + ', ' + j + ')'); td.appendChild(text); } tr.appendChild(td); } tbody.appendChild(tr); } table.appendChild(tbody); elem.appendChild(table); } // 生成したElementをbodyにつなげるのは最後 createInner(area, DEPTH); } /** * Elementを生成したそばからbodyにつなげて複雑な構造をつくる */ function createComplexDOM2(area) { function createInner(elem, depth) { // 生成したElementをどんどんbodyにつなげていく var table = document.createElement("TABLE"); elem.appendChild(table); table.border = 1; table.cellSpacing = 0; table.cellPadding = 2; var tbody = document.createElement("TBODY"); table.appendChild(tbody); for (var i = 0; i < ROWS; i++) { var tr = document.createElement("TR"); tbody.appendChild(tr); for (var j = 0; j < COLS; j++) { var td = document.createElement("TD"); tr.appendChild(td); if (depth > 0) { createInner(td, depth - 1); } else { var text = document.createTextNode('DOM (' + i + ', ' + j + ')'); td.appendChild(text); } } } } createInner(area, DEPTH); } /** * 複雑なHTMLを作ってinnerHTMLに代入する */ function createComplexHTML(area) { function createInner(depth) { html.push('<table border="1" cellspacing="0" cellpadding="2"><tbody>'); for (var i = 0; i < ROWS; i++) { html.push('<tr>'); for (var j = 0; j < COLS; j++) { html.push('<td>'); if (depth > 0) { createInner(depth - 1); } else { html.push('innerHTML (' + i + ', ' + j + ')'); } html.push('</td>'); } html.push('</tr>'); } html.push('</tbody></table>'); } var html = []; createInner(DEPTH); area.innerHTML = html.join("\n"); } /** * メソッドを実行して実行時間を記録する */ function test(func, id) { func.results = func.results || []; var area = document.getElementById('test'); area.innerHTML = ""; var begin = new Date().getTime(); func(area); var end = new Date().getTime(); func.results.push(end - begin); // 記録をtableにして表示する var html = []; html.push('<table border="1" cellspacing="0" cellpadding="2"><tbody>'); for (var i = 0; i < func.results.length; i++) { html.push('<tr><td>' + i + '</td><td>' + func.results[i] + 'ms</td></tr>'); } html.push('</tbody></table>'); document.getElementById(id).innerHTML = html.join("\n"); }

この記事に対するコメント

この記事に対するコメントの投稿



管理者にだけ表示を許可する

この記事に対するトラックバック

トラックバックURL
http://tockri.blog78.fc2.com/tb.php/9-adadfdb5
この記事にトラックバックする(FC2ブログユーザー)

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。