吉本集の個人ブログ
Web制作の技術について書いています。たまに日記も書きます。

【JS入門】DocumentFragmentインタフェースを使用したノードの追加

2018年2月8日 / category : javascript

今回の記事ではDocumentFragmentインタフェースについて解説したいと思います。前回の記事「DOMについて Vol.5(ノードの生成・追加・複製・削除)」の中で、次のようなコードを推奨できないコードと紹介しました。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>タイトル</title>
</head>
<body>
<div>
<ul id="list"></ul>
</div>
<script src="./js/sample.js"></script>
</body>
</html>
sample.js
const list = document.getElementById('list');
const listItem = document.createElement('li');
listItem.textContent = 'リストアイテム';
listItem.className = 'item';
const len = 3;
let clone;
for( let i=0; i<len; i++ ){
	clone = listItem.cloneNode(true);
	clone.textContent += (i+1) + '番目';
	list.appendChild(clone);
};

上のコードを簡単に解説すると、for文によってli要素が3回、ul要素に追加されています。ul要素に追加する際、メソッドappendChildを実行していますが、DOMオブジェクトが変更される度、ブラウザに搭載されているレンダリングエンジンによって、レイアウト(リフロー)が実行されます。(ここで使うレイアウトとは、ブラウザが画面の一部または全体を再レンダリングすることを言います。)そのため、上のコードの場合、3回のレイアウト(リフロー)が行われることになります。プログラムをする場合、処理効率を考慮した実装を求められますので、極力レイアウト(リフロー)の回数を抑えたプログラムが理想になります。
上のコードの場合、DocumentFragmentインタフェースを使用することで、理想的なプログラムにすることができます。

メソッドcreateDocumentFragmentを使用する

Documentインターフェイスに、メソッドcreateDocumentFragmentが定義されています。このメソッドを使用することで、空のDocumentFragmentオブジェクトを生成することができます。DocumentFragmentオブジェクトは、特殊なDOMオブジェクトでメモリ上にのみ存在し、DOMツリーの一部にはなりません。レンダリングエンジンによる描画の対象にはなりません。そのためDocumentFragmentオブジェクトへDOMオブジェクトを追加してもレイアウト(リフロー)の処理が行われません。これはパフォーマンスに大きく貢献します。

Document.createDocumentFragment():空のDocumentFragmentオブジェクトを生成する。
戻り値(return): DocumentFragment
構文

let docFrag = document.createDocumentFragment();

sample.js
const list = document.getElementById('list');
const docFrag = document.createDocumentFragment();
const listItem = document.createElement('li');
listItem.textContent = 'リストアイテム';
listItem.className = 'item';
const len = 3;
let clone;
for( let i=0; i<len; i++ ){
	clone = listItem.cloneNode(true);
	clone.textContent += (i+1) + '番目';
	docFrag.appendChild(clone);
};
list.appendChild(docFrag);

DocumentFragmentインターフェイスは、Nodeインターフェイスを継承しているのでメソッドappendChildを使用することができます。DocumentFragmentオブジェクトを参照している変数docFragに、li要素を追加します。このとき、メソッドappendChildを実行していますが、レイアウト(リフロー)の処理は行われません。最後に変数docFragをul要素に追加することで、ul要素にli要素が追加されます。この一連のフローを図にします。

DocumentFragmentオブジェクトを使用することでレイアウト(リフロー)の処理を抑えることができました。
DocumentFragmentオブジェクトは、コンストラクタ関数を使用してオブジェクトを生成することもできますので、次のコードもメソッドcreateDocumentFragmentを使用したコードを同様の結果になります。

sample.js
const list = document.getElementById('list');
const docFrag = new DocumentFragment();
const listItem = document.createElement('li');
listItem.textContent = 'リストアイテム';
listItem.className = 'item';
const len = 3;
let clone;
for( let i=0; i<len; i++ ){
	clone = listItem.cloneNode(true);
	clone.textContent += (i+1) + '番目';
	docFrag.appendChild(clone);
};
list.appendChild(docFrag);