使用JavaScript更新html方法的主体

xzv2uavs  于 2022-12-25  发布在  Java
关注(0)|答案(3)|浏览(95)

我正在尝试使用javascript更新html表的正文。
有两种方法可以实现这一点
html表格:

<table>
     <thead>
      <tr>
        <th>Title</th>
      </tr>
     </thead>
     <tbody>
     </tbody>
    </table>

方法1(字符串插值):

document.querySelector('table tbody').innerHTML= 
    '<tr><td>some text</td></tr><tr><td>some text</td></tr>'

方法二:

const table = document.querySelector("table");
    const row = table.insertRow(0);
    const cell1 = row.insertCell(0);
    cell1.innerHTML = 'some text';

哪种方法的性能更好?为什么?
假设每1秒我们必须更新表的整个主体,并且我们有100行
注意:我只想了解性能,而忽略安全性等其他问题

vulvrdjw

vulvrdjw1#

我们用1000次表体更新来测试性能,为了比较,两种方法都是每次更新100行来替换整张表:

function method1() {
  // add 100 rows:
  document.querySelector('#method1 tbody').innerHTML = '<tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr> <tr><td>some text</td></tr>';
}

function method2() {
  const tbody = document.querySelector('#method2 tbody');
  tbody.innerHTML = '';
  // add 100 rows:
  for(let i = 1; i <= 100; i++) {
    tbody.insertRow(0).insertCell(0).innerHTML = `row ${i} text`;
  }
}

let start = new Date();
for(let i = 0; i < 1000; i++) {
  method1();
}
let end = new Date();
console.log('method1:', end - start, 'ms');

start = new Date();
for(let i = 0; i < 1000; i++) {
  method2();
}
end = new Date();
console.log('method2:', end - start, 'ms');
<table id="method1">
 <thead>
  <tr>
    <th>Method 1</th>
  </tr>
 </thead>
 <tbody>
 </tbody>
</table>
<table id="method2">
 <thead>
  <tr>
    <th>Method 2</th>
  </tr>
 </thead>
 <tbody>
 </tbody>
</table>

控制台日志:

method1: 178 ms
method2: 463 ms

正如所猜测的那样,method1比method2快2.5倍,这是有道理的,因为要替换method2中的tbody,首先需要清空它,并且有200个方法调用,而不是一次更新。

nbysray5

nbysray52#

尽可能避免更改DOM

作为前端开发人员,我们要处理的消耗资源最多的操作之一就是对DOM的更改。回流和重绘涉及到浏览器必须处理的大量计算,因此要将交互和对DOM的更改保持在最低限度。我们可以添加、删除并通过使用documentFragment作为构建的临时文档来修改HTML和文本。t附加到DOM,因此对docFrag执行的任何操作都不会影响DOM。
测试A测试B中,所有操作都是在docFrag上完成的--每个测试DOM将有2次重画和2次回流。为了充分理解回流和重画的危害,转到此test suite。其中有4个测试用例TEST ATEST B与此答案中提供的堆栈代码段相同--TEST C测试A没有docFrag,测试D测试B没有docFrag。至于测试C/D触发了多少次回流/重画,我没有费心去计数(我们可以安全地假设远远超过微不足道的2测试A/B)。

    • 注:**所有测试(SnippetsBenches)具有相同的数据输入,由100行和3列的多维数组组成,每个单元格的内容为3位数。

JSBench.Me - TEST A/B/C/D

获胜者是...

试验A占优势🥇

测试A

documentFragment和HTML表格元素方法

const data=[[591,917,494],[198,200,592],[319,593,343],[149,708,760],[289,132,762],[966,587,225],[921,510,888],[175,283,918],[944,852,330],[537,518,558],[896,927,461],[324,360,719],[800,421,524],[634,868,548],[182,340,239],[636,760,786],[860,744,616],[213,512,587],[274,236,190],[861,996,552],[761,649,814],[121,471,554],[385,538,813],[802,522,861],[468,479,870],[209,238,180],[210,314,782],[682,581,644],[996,375,580],[635,586,252],[538,640,141],[650,788,716],[654,666,578],[583,573,787],[948,968,708],[993,177,355],[404,187,596],[275,312,556],[820,481,133],[598,541,618],[424,574,753],[271,257,560],[294,246,553],[240,698,833],[860,597,219],[796,295,378],[497,834,902],[168,647,239],[745,988,788],[572,356,490],[274,957,519],[698,402,673],[798,522,743],[595,677,416],[369,786,154],[691,424,502],[465,820,533],[827,966,761],[297,947,385],[817,930,803],[609,567,369],[223,981,890],[275,387,404],[407,578,779],[713,595,428],[499,986,421],[241,310,591],[713,328,239],[152,949,826],[438,840,708],[478,114,571],[274,304,105],[239,253,916],[573,281,263],[179,502,936],[725,639,245],[467,542,488],[515,923,784],[464,258,573],[582,709,761],[138,734,836],[376,572,680],[361,478,709],[924,683,538],[379,677,378],[435,850,167],[950,546,976],[236,724,194],[314,525,639],[362,715,573],[320,965,799],[973,717,627],[122,856,371],[169,702,269],[580,826,127],[949,530,791],[625,845,701],[748,570,277],[669,955,453],[279,239,867]];

const T = document.querySelector("table");

const genData = (table, tArray) => {
  let R = tArray.length;
  let C = tArray[0].length;
  const tB = document.createElement("tbody");
  const frag = document.createDocumentFragment();
  
  for (let r=0; r < R; r++) {
    let row = tB.insertRow();
    for (let c=0; c < C; c++) {
      row.insertCell().textContent = tArray[r][c];
    }
  }
  table.tBodies[0].remove(); // 1 reflow 1 repaint
  frag.append(tB);
  table.append(frag); // 1 reflow 1 repaint
}

genData(T, data);
<table>
  <thead>
    <tr>
      <th>A</th>
      <th>B</th>
      <th>C</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>

测试B

documentFragment和呈现HTML

一个二个一个一个

fcwjkofz

fcwjkofz3#

JS代码更快!

自己测试...
使用文本意味着使用HTML解释器来生成DOM元素,而JS代码直接完成这一工作,这里特别优化了处理html表格。

const 
  tableBody1 = document.querySelector('#method1 tbody')
, tableBody2 = document.querySelector('#method2 tbody')
, loopMax      = 50
, replacements = 100
  ;
function method1()
  {
  tableBody1.innerHTML += '<tr><td>some text</td></tr><tr><td>some text</td></tr>';
  }
function method2()
  {
  tableBody2.insertRow().insertCell().textContent = 'some text'; 
  tableBody2.insertRow().insertCell().textContent = 'some text'; 
  }
console.time('method 1 - HTML') 
for (let rep = replacements; rep--;)
  {
  tableBody1.innerHTML = '';
  for (let i = 0; i < loopMax; i++) method1();  
  }
console.timeEnd('method 1 - HTML') 

console.time('method 2 - JS code') 
for (let rep = replacements; rep--;)
  {
  tableBody2.innerHTML = '';
  for (let i = 0; i < loopMax; i++) method2();
  }
console.timeEnd('method 2 - JS code')
<table id="method1">
 <thead> <tr> <th>Method 1</th> </tr> </thead>
 <tbody></tbody>
</table>
<table id="method2">
 <thead> <tr> <th>Method 2</th> </tr> </thead>
 <tbody></tbody>
</table>

相关问题