要素を追加するappendメソッドについて

スタッフブログ

こんにちは、今年もまた1年が始まりましたね。新人ソフトウェアエンジニアの森山です。皆さんはJavaScriptでHTMLElementを追加するときにどんなメソッドを使いますか?私は初めに勉強したときから「appendChild」というメソッドを使っていました。また、appendというメソッドがchromeブラウザのコンソール画面にてコード補完で表示されていたので調べたことがあったのですが、検索上位に出てきたものはjQueryについて書かれているものばかりだったためjQueryを使わない私はほとんど気にせず無視していました。しかし、jQueryを読み込んでいないのにappendが表示されている点が気になり、詳しく調べてみるとjQuery以外にもDOM操作のappendメソッドを発見しました。ということで今回はappendChildを基準に、似た機能を持っているメソッドとの違いについて紹介します。

要素を追加するappendメソッド

このappendメソッドですが、どうやらParentNodeのメソッドに存在するみたいでした。ParentNodeはミックスインであり、ElementとDocument、DocumentFragmentオブジェクトに実装されているそうです。ちなみに、ParentNodeの他のメソッドやプロパティにはquerySelectorやchildrenがありました。なのでこれらが使える要素と考えれば分かりやすいかもしれません。

何が違うのか

appendChildメソッドとappendメソッドの違いについて触れていきたいと思います。また、同じ名前で実装されているjQueryのappendメソッドとの違いも気になったのでこちらも調べて見ました。

Node.appendChilde

このメソッドでは、引数にNodeを1つだけ指定する必要があります。また、ここで言うノードにはHTMLElementとTextノードの二種類があります。なので文字を要素内に入れたい場合はdocumentのcreateTextNodeなどを使ってTextノードを生成してから入れる必要があります。

ParentNode.append

このメソッドは引数に複数のNodeもしくは文字列を指定できます。appendChildと違う点として、引数に文字列を指定できるのと複数の引数が処理できるという点です。文字列を指定した場合は子要素にTextノードとして追加され、複数指定した場合は先から順番に子要素へ追加されます。また、互換性の問題があるためInternetExplorerでは使用できません。

jQuery.append

このappendメソッドはParentNodeのappendメソッドと動きはほぼ同じでNodeか文字列を複数指定できます。ですが、違う点として文字列を指定したときの動きが違います。ParentNodeではTextノードを追加していましたが、jQueryではHTML文字列として解釈されます。

実行速度

ここまで紹介してきた物はそれぞれ似ているためどれを使えば良いかというのを決める点として実行速度も1つの基準になると思います。ということでHTMLElementの追加、Textノードの追加、Node以外の文字列追加の実行速度をconsole.time()で図ってみました。

HTMLElementの追加

まずはHTMLElementの追加で、今回使用したコードはこちらです。

//HTMLElementの追加 jQuery.append
const div = $(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    const putElement = document.createElement("div");
    div.append(putElement);
}
console.timeEnd();

//HTMLElementの追加 ParentNode.append
const div = document.querySelector(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    const putElement = document.createElement("div");
    div.append(putElement);
}
console.timeEnd();

//HTMLElementの追加 Node.appendChild
const div = document.querySelector(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    const putElement = document.createElement("div");
    div.appendChild(putElement);
}
console.timeEnd();

このコードはそれぞれ、div要素を生成して各自のメソッドを使って1万個追加する処理です。これを各種を10回づつ測定し、平均を出しました。

使用したメソッド div要素を生成して追加する
jQuery.append 63.739 ms
ParentNode.append 9.018 ms
Node.appendChild 8.216 ms

最速はNode.appendChildという結果になりました。とくにこだわりが無ければNode.appendChildを使っておけばいいのではないでしょうか。しかし、よく言われるjQueryの実行が遅いというのが表にすると一目瞭然です。大体速度は8分の1ぐらいなのでもし選べるのであればjQuery以外のメソッドを使いたいですね。

Textノードの追加

次にTextノードの追加で、今回使用したコードはこちらです。

//Textノードの追加 jQuery.append
const div = $(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    const putElement = document.createTextNode("テスト文章");
    div.append(putElement);
}
console.timeEnd();

//Textノードの追加 ParentNode.append
const div = document.querySelector(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    const putElement = document.createTextNode("テスト文章");
    div.append(putElement);
}
console.timeEnd();

//Textノードの追加 Node.appendChild
const div = document.querySelector(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    const putElement = document.createTextNode("テスト文章");
    div.appendChild(putElement);
}
console.timeEnd();

このコードはそれぞれ、「テスト文章」の文字のTextノードを生成して各自のメソッドを使って1万個追加する処理です。これもまたそれぞれ10回づつ測定し、平均を出しました。

使用したメソッド Textノードを生成して追加する
jQuery.append 42.596 ms
ParentNode.append 7.104 ms
Node.appendChild 6.28 ms

またしても最速はNode.appendChildという結果になりました。今回は前回よりも実行速度が全体的に速いですが、やはりNode.appendChild使っておけば良いのではないでしょうか。これもjQueryが頭1つとびぬけて遅い結果になりました。

文字列の追加

最後に文字列を引数に渡した場合ですが、Node.appendChildには文字列を指定することができないのでTextノードを生成して追加した結果のみ載せています。また、jQueryのappendも生成されるものは同じですが、HTML文字列を指定した場合はタグを生成するので同じ結果の出るinsertAdjacentHTMLの結果も測定しました。

//文字列の指定 jQuery.append
const div = $(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    div.append("テスト文章");
}
console.timeEnd();

//文字列の指定 element.insertAdjacentHTML
const div = document.querySelector(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    div.insertAdjacentHTML("beforeend", "テスト文章");
}
console.timeEnd();

//文字列の指定 ParentNode.append
const div = document.querySelector(".target");

console.time();
for (let i = 0; i < 10000; i++) {
    div.append("テスト文章");
}
console.timeEnd();

上のコードはそれぞれ、各自のメソッドを使って「テスト文章」の文字のTextノードが含まれているdivを生成して1万個追加する処理です。下のコードは、「テスト文章」の文字のTextノードを生成してParentNodeのappendメソッドを使って1万個追加する処理です。これらも同じくそれぞれ10回づつ測定し、平均を出しました。

使用したメソッド 引数に文字を指定する Textノードを生成して追加する
jQuery.append 42.862 ms --
element.insertAdjacentHTML 21.218 ms --
ParentNode.append 4.72 ms 7.104 ms
Node.appendChild -- 6.28 ms

今回の最速はParentNode.appendになりました。ParentNode.appendを実行して得られる結果は1つ前の項目でやっていたTextノードを生成して追加するという行動と同じなのですが、生成してから追加するよりも確実に速くなっています。個人的な予想としてあらかじめ作って追加するほうが速くできると思っていたのですが、いい意味で予想を裏切られました。

まとめ

ということで今回はHTMLElementの最後にNodeを追加する機能の違いについて比べてみました。全体的に実行速度が速いのはNodeのappendChildeメソッドでしたが、テキストノードを追加する処理に限りParentNodeのappendメソッドの方が速くなるという結果になりました。また、私はjQueryをほとんど知らなかったのですが、やはり動作が遅いということを実際に数値として確認する事ができました。今年も今回みたいに知らないメソッドの勉強など、プログラム等の勉強を頑張っていきたいと思います。