知りたいこと
<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();
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。