質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

意見交換

6回答

383閲覧

JavaScript で大量の <my-li> 生成は、【+=】か【createElement】か?

munekun

総合スコア108

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2025/04/10 02:16

編集2025/04/10 02:30

知りたいこと

<li> の場合なら【createElement】よりも速い【+=】を使うべき [※1] だが、ではカスタム要素 <my-li> ではどうすべきか?

疑問の詳細

<my-li>🚗速い のは【+=】でしょうけれど、しかし文字列では HTML 生成にあたって必要な値をデータ属性で渡さねばならず、 ❌無駄なデータ属性 を持つことになってしまいます。

【+=】の場合

例えば以下は user.name<my-li> の中に表示するため、わざわざ data-name にも渡さねばならず、HTMLとしては ❌無駄なデータ属性 が必要になります。(しかし 🚗速い というメリットがあります。)

JavaScript

1import htmlTemplates from "./htmlTemplates.js" 2 3class MyLi extends HTMLElement { 4 constructor() { 5 super(); 6 } 7 8 connectedCallback() { 9 this.name = this.dataset.name; 10 this.render(); 11 } 12 13 render() { 14 this.replaceChildren(); 15 16 this.insertAdjacentHTML( 17 "beforeend", 18 htmlTemplates.userBox(this.name) 19 ); 20 } 21} 22 23const users = [ 24 {name: "taro"} 25]; 26 27const container = document.createElement('ul'); 28 29foreach (users as user) { 30 html += ` 31 <my-li data-name="${user.name}"> <!-- ❌無駄なデータ属性 --> 32 </my-li>`; 33} 34container.insertAdjacentHTML('beforeend', html); // 🚗速い
【createElement】の場合

こちらは createElement() したオブジェクトに対して user.name✅自然にセット しており、その値を userBox() に渡すことができるので、上記【+=】のように ❌無駄なデータ属性 が不要になります。(しかし 🐢遅い というデメリットがあります。)

JavaScript

1import htmlTemplates from "./htmlTemplates.js" 2 3class MyLi extends HTMLElement { 4 constructor() { 5 super(); 6 } 7 8 connectedCallback() { 9 this.render(); 10 } 11 12 render() { 13 this.replaceChildren(); 14 15 this.insertAdjacentHTML( 16 "beforeend", 17 htmlTemplates.userBox(this.name) 18 ); 19 } 20} 21 22const users = [ 23 {name: "taro"} 24]; 25 26const container = document.createElement('ul'); 27foreach (users as user) { 28 const myLi = document.createElement('my-li'); 29 myLi.name = user.name; // ✅自然にセット 30 container.appendChild(myLi); // 🐢遅い 31}

ということで、

無駄な値を許容しても、速度を優先すべきなのか?
無駄な値を排除して、速度を犠牲にすべきなのか?

ついてのご意見を募集させてください。(明確な正解があるか否かわからないため、質問でなく意見交換として投稿させて頂きました。)

もちろん、いずれよりも優れた正解があればぜひそれについてもご回答を募集しております。

補足

冒頭の [※1] については以下を試し、どうやら【createElement】より【+=】の方が速いっぽいという判断です。
(尚 createDocumentFragment() はめちゃ遅かったです。)

テストコード

https://jsfiddle.net/k39f1j8L/

JavaScript

1// テスト用のコンテナを作成 2const container = document.createElement('ul'); 3document.body.appendChild(container); 4 5// 10000件のアイテムを生成するためのテスト 6const totalItems = 100000; 7 8// insertAdjacentHTML を使用する場合 9function testInsertAdjacentHTML() { 10 const start = performance.now(); // 開始時刻 11 12 let html = ''; 13 for (let i = 0; i < totalItems; i++) { 14 html += `<li>【+=】${i}</li>`; 15 } 16 17 container.insertAdjacentHTML('beforeend', html); // 一括で挿入 18 19 const end = performance.now(); // 終了時刻 20 console.log('insertAdjacentHTML elapsed time: ', end - start, 'ms'); 21} 22 23// createElement を使用する場合 24function testCreateElement() { 25 const start = performance.now(); // 開始時刻 26 27 for (let i = 0; i < totalItems; i++) { 28 const li = document.createElement('li'); 29 li.textContent = `【createElement】${i}`; 30 container.appendChild(li); // 1件ずつ挿入 31 } 32 33 const end = performance.now(); // 終了時刻 34 console.log('createElement elapsed time: ', end - start, 'ms'); 35} 36 37// テスト実行 38testInsertAdjacentHTML(); 39testCreateElement();

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

回答6

#1

utm.

総合スコア752

投稿2025/04/10 02:49

  1. JavaScriptで速度にこだわる必要性はほとんどの場合ない(オーバーエンジニアリング)
  2. 適切なレイヤーの考えがあればHTMLの属性に無駄である、無駄でないという発想をする必要は無い(意味がある、意味が無いという観点しかない)
  3. Node(DOM)はオブジェクトなので、プロパティの参照とHTMLの構造を混ぜて考えるのはナンセンス

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#2

yambejp

総合スコア117548

投稿2025/04/10 03:18

一箇所に大量のDOMを挿入する動的なDOM処理について速さを求めるのであればDocumentFragmentが有利ですね。メンテナンス性を考えればDOMではなくテキストベースで作ってinsertAdjacentElementする手もあるのでこだわりがないなら選択肢になるかもしれません。テキストからHTML要素を発生させるのは別の課題がありますけどね

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#3

maisumakun

総合スコア146503

投稿2025/04/10 04:11

スピード云々以前の問題として、XSSの危険を考えれば、「変数代入をやるような文字列からHTMLを生成する」というのは真っ先に候補から外れます。


エレメントは1つだけ生成して、残りはcloneNodeするというのはどうでしょうか。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#4

munekun

総合スコア108

投稿2025/04/10 07:53

#1

ありがとうございます。
いきなり正解でたっぽいですね。

オーバーエンジニアリング

この言葉、初耳でした。
何を避けるべきかわかっていないので無駄なコストをかけがちですが、言葉を知れるとコストを避けるための気づきのフックになってくれそうです。

プロパティの参照とHTMLの構造を混ぜて考える

なるほど。そもそもこういうものだからそれに従うとこう。と、いつも根本的な切り口でとても腹落ちです。

#2

ありがとうございます。

DocumentFragment

これ、早いかと思ったのですが、一番遅かったんですよね。
https://jsfiddle.net/mvyq2d7r/

#3

ありがとうございます。

XSSの危険

なるほど、多少の速度のメリットなんかよりも、XSSは圧倒的に避けるべきリスクでしたね。

cloneNode

クローンですか、なるほど。この考えはありませんでしたが、ちょっと他より遅くなるかもです。
https://jsfiddle.net/mvyq2d7r/

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#5

yambejp

総合スコア117548

投稿2025/04/10 08:09

編集2025/04/10 08:12

#4

フラグメントの有利なところは、文法上必要なコンテナを設定してなくてもまとめて投入ができることです。
たとえばliを復数生成した場合、ulに投入するにはひとつひとつappendChildしないといけませんが、フラグメントで処理する場合はliを並行投入しておいて最後にulに1回appendChildするだけですみます。DOM処理の速度の付加はDOM自体を投入する作業が大きいので適正にフラグメントを利用すると理論上はかなり高速に処理ができるはずです。

参考

html

1<script> 2const max=100; 3function insert1(){ 4 for(let i=1;i<=max;i++){ 5 ul1.appendChild(Object.assign(document.createElement('li'),{textContent:i})); 6 } 7} 8function insert2(){ 9 const frg = document.createDocumentFragment(); 10 for(let i=1;i<=max;i++){ 11 frg.appendChild(Object.assign(document.createElement('li'),{textContent:i})); 12 } 13 ul2.appendChild(frg); 14} 15</script> 16<input type="button" value="1" onclick="insert1()"> 17<input type="button" value="2" onclick="insert2()"> 18<ul id="ul1"></ul> 19<ul id="ul2"></ul>

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#6

munekun

総合スコア108

投稿2025/04/10 08:56

#5

たびたびありがとうございます。
なるほど、同じ DOM へのアプローチではあっても createElement は都度 DOM にセットするのに対して createDocumentFragment は仮セットみたいなことをしてから一括で DOM にセットできる。という感じですね。大きな差になりそうです。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

この意見交換はまだ受付中です。

会員登録して回答してみよう

アカウントをお持ちの方は

関連した質問