JavaScript: 要素(タグ)の追加に時間がかかる場合の対処
JavaScriptで要素を追加する処理が必要なプログラムを作成するとき、大きくわけて2つの方法があります。
- 1: 親になる要素(タグ)の
innerHTML
にタグの文字列をセットする- 1-1: 1つずつ innerHTML に
+=
でタグを追加していく - 1-2: 文字列変数に
+=
でタグ文字列をためておいて、最後にinnerHTML
にセットする
- 1-1: 1つずつ innerHTML に
- 2: 親になる要素(タグ)の
appendChild()
を呼び出して、タグのDOMオブジェクトを追加する- 2-1: 1つずつ
appendChild()
でDOMオブジェクトを追加していく - 2-2:
DocumentFragment
と呼ばれる一時的な器に対してDOMオブジェクトをappendChild()
しておいて、すべて追加し終わったら親になる要素にDocumentFragment
をappendChild()
する
- 2-1: 1つずつ
jQueryを使用している場合でも、内部では最終的に上記のいずれかになります。
( html()
でのセットは 1、 append()
は 2 です)
少量の要素を追加する場合は、基本的にどれを使っても問題になることはあまりありません。
大量の要素を追加する場合は、1-1 や 2-1 だと速度が遅くなっていくのがわかるようになってきます。 1つ要素を追加するたびに、ブラウザ側で調整(リフロー)や再描画が発生するためです。 そのため、1-1 や 2-1 を使っていたら、 1-2 や 2-2 を使うようにしてください。
また、IE11の場合は 2-2 も遅いため、できるだけ 1-2 を使用するとよいです。
(innerHTML
を可能な限り避けたい場合は、 document.createRange().createContextualFragment(タグ文字列)
として得られた DocumentFragment
を 1回だけ appendChild()
する方法も取れます )
動作の確認 (10,000個のタグの追加)
※ jQueryなどのライブラリを使わない、純粋なJavaScriptだけの簡単なコードにしています。
(1-1: 1つずつ innerHTML +=
で追加。実行するととても遅くなるので注意してください)
(1-2: 最後に innerHTML =
で追加)
(2-1: 1つずつ appendChild()
で追加。実行するととても遅くなるので注意してください)
(2-2: 最後に appendChild()
で DocumentFragment
を追加)
IE11の場合
IE11だと、2-2 (DocumentFragmentに appendChild()
) も、遅いです。
appendChild()
などのDOM操作自体が遅く、実行されるたびに他のブラウザに比べて遅くなっていきます。
( IE11の開発者ツールから 2-2 のパフォーマンスを確認した例。 createElement()
appendChild()
などがされるたびに時間がかかっている )
innerHTMLの場合は、2-1よりも少ない時間になっています。
( IE11の開発者ツールから 1-2 のパフォーマンスを確認した例 )