【问题标题】:Optimization issue when creating dynamic HTML element inside loop在循环内创建动态 HTML 元素时的优化问题
【发布时间】:2022-01-17 16:14:37
【问题描述】:

我有一组预设的单词,我想在每个条目后随机化并映射空格,然后拆分为单个字符,然后将这些字符作为单独的<div> 放入一个 html 元素中。到目前为止,我有这个确实有效,但它比 150-200 字符有点慢,我猜这是可以理解的。我需要每个角色都在它自己的 <div> 中,所以我不确定如何优化它。

我有一个类似于下面代码sn-p的算法结构。在循环中渲染大量动态 HTML 元素时如何避免优化问题?

let container = document.getElementById('container');
let arr = ['one', 'two', 'three', 'four'];
let currentIndex = arr.length;
let current__text = [], count, randomIndex;

while (currentIndex != 0) {
  randomIndex = Math.floor(Math.random() * currentIndex);
  --currentIndex;
  [current__text[currentIndex], arr[randomIndex]] = [
    current__text[randomIndex], arr[currentIndex]];
}
  
arr = arr.slice(0, count).map(e => e + ' ').join('').split('');

arr.pop();

for (item of arr) {
  container.innerHTML += `<div class="char">${item}</div>`;
}
#container{}

.char{}
&lt;div id="container"&gt;&lt;/div&gt;

【问题讨论】:

  • 无关说明:开始使用分号。不使用分号很容易降低代码的可读性,甚至在某些极端情况下导致错误。
  • 你能举一个预期输出的例子吗?
  • 因为这个原因很慢:container.innerHTML += ...。不要在循环中设置innerHTML(它会在每一轮中重新创建container 的所有HTML 并强制进行布局计算),而是使用insertAdjacentHTML,或者更确切地说动态创建元素,将它们附加到@ 987654331@,然后将 documentFragment 附加到 DOM。此外,使用 styleSheet 而不是附加内联样式可能会加快创建过程。
  • @Teemu 你是个救星。你是对的,innerHTML += 是问题所在......现在它更快了。谢谢!
  • @Sercan Setting innerHTML DOM 中的一个元素只能用于一个目的,使一个元素为空,它不应该用于做任何其他事情。只需阅读documentation 中的所有建议和警告。

标签: javascript arrays algorithm optimization time-complexity


【解决方案1】:

您开发的大多数算法对结果没有影响。我开发的解决方案中的printArray()方法和你现在做的一样。

我将@Teemu指定的更改添加到程序中并比较了结果。正如@Teemu 指出的那样,Element.insertAdjacentHTML() 方法对Element.innerHTML 属性非常快。下面是运行时的比较:

Duration (insertAdjacentHTML): 2.7000000029802322 milliseconds
Duration (innerHTML):          85.70000000298023  milliseconds

注意: 为了比较 Element.insertAdjacentHTML() 方法和 Element.innerHTML 属性的运行时差异,我将 none 分配给 .char 类样式的 display 属性,所以一个元素不会打印在屏幕上。

let container = document.getElementById('container');
let firstArray = [], secondArray = [];

function measurePerformance(method, mode, array){
  var startTime = performance.now();
  method(mode, array);
  var endTime = performance.now();
  console.log(`Duration (${mode}): ${endTime - startTime} milliseconds`);
}

function generateArray(firstArray, secondArray){
  for(let i = 100 ; i > 50 ; --i){
    firstArray.push(i);
    secondArray.push(i);
  }
}

function printArray(mode, array){
  array = array.map(e => e + ' ').join('').split('');
  
  if(mode === "insertAdjacentHTML"){
    for(item of array){
      container.insertAdjacentHTML("beforeend", `<div class="char">${item}</div>`);
    }
  }
  else if(mode === "innerHTML"){
    for(item of array){
      container.innerHTML += `<div class="char">${item}</div>`;
    }
  }
}

generateArray(firstArray, secondArray);
measurePerformance(printArray, "insertAdjacentHTML", firstArray);
measurePerformance(printArray, "innerHTML", secondArray);
.char{
  background-color: yellow;
  border: 1px solid gray;
  margin-bottom: 2px;
  display: none;
}
&lt;div id="container"&gt;&lt;/div&gt;

【讨论】:

  • 我通过使用更大的数组添加了更多challenge to the test。值得注意的是,当控制台说任务完成时渲染仍在运行(仅 JS 部分完成)。 documentFragment 的速度似乎是 insertAdjacentHTML 的两倍左右。如果我们渲染一个大的表格元素,我相信差距会更大。
  • 感谢@Teemu,它让它变得更快。
  • @vvhitearmor 是的,通常更多的代码在速度方面更有效率。
【解决方案2】:

要创建您需要的字母:

arr = ['one', 'two', 'three', 'four'];

const output = arr.map(
    (word) => word.trim().split('')
);

console.log(output)

我没有在我的答案中添加 HTML 部分。如果您需要这方面的帮助,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-19
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    相关资源
    最近更新 更多