使用 innerHTML 和 += 缓慢创建 div

Slow creation of divs using innerHTML and +=

我目前正在从数据库中检索大量信息,并希望在网站上以缩图形式显示这些信息。从数据库中收集的每一行都包含一张图像和一些其他出现在微缩模型中的信息。

收集信息后,我使用了一个名为 printAllMini 的函数,它使用 printMini[=] 将所有 div 打印到容器中48=]每行信息。

printAllMini = function() {
    console.log("PRINTING!");
    document.getElementById("mini_blocks").innerHTML = "";
    for (var i = 0; i < docs.length; i++) {
 var object = docs[i];
 printMini(object.id, object.arrived, object.booked, object.verification, object.org, object.price, object.stax, object.pic);
 console.log(i);
    }
    console.log("DONE!");
}

printMini = function(id, arrived, booked, verification, org, price, stax, pic) {
    if (verification != "-") {
 // So that no string is empty
 if (id == "") { id = "-"; }
 if (arrived == "") { arrived = "-"; }
 if (booked == "") { booked = "-"; }
 if (verification == "") { verification = "-"; }
 if (org == "") { org = "-"; }
 if (price == "") { price = "-"; }
 if (stax == "") { stax = "-"; }
 document.getElementById("mini_blocks").innerHTML += '<div class="mini" id="\'' + id + '\'" onclick="changeInfo(\'' + arrived + '\', \'' + booked + '\', \'' + verification + '\', \'' + org + '\', \'' + price + '\', \'' + stax + '\', \'' + id + '\'), getPDF2(\'' + id + '\')"> <div class="mini_header"> <table class="mini_table"> <tr> <td align="left"> <b>Inkommen</b> </td> <td align="right"> <b>ID</b> </td> </tr> <tr> <td align="left">' + arrived + '</td> <td align="right">' + id + '</td> </tr> </table> </div> <div class="mini_img"> <img src="data:image/jpeg;base64,' + pic + '"> </div> <div class="mini_footer"> <table class="mini_table"> <tr> <td align="left"> <b>Bokförd</b> </td> <td align="right"> <b>Verifikat</b> </td> </tr> <tr> <td align="left">' + booked + '</td> <td align="right">' + verification + '</td> </tr> </table> </div> </div>';
    }
    else {
 document.getElementById("mini_blocks").innerHTML += '<div class="mini" id="\'' + id + '\'" onclick="changeInfo(\'' + arrived + '\', \'' + booked + '\', \'' + verification + '\', \'' + org + '\', \'' + price + '\', \'' + stax + '\', \'' + id + '\'), getPDF2(\'' + id + '\')"> <div class="mini_header2"> <table class="mini_table"> <tr> <td align="left"> <b>Inkommen</b> </td> <td align="right"> <b>ID</b> </td> </tr> <tr> <td align="left">' + arrived + '</td> <td align="right">' + id + '</td> </tr> </table> </div> <div class="mini_img"> <img src="data:image/jpeg;base64,' + pic + '"> </div> <div class="mini_footer2"> </div> </div>';
    }
}

问题:

但是这真的很慢,需要超过 45 秒才能完成。似乎与以下行有关:

document.getElementById("mini_blocks").innerHTML += '<div'>;

...因为创建 div 的时间越来越长。前 10 个 div 是在第一秒内创建的,但到最后,大约每秒创建一个 div。它只会越来越慢。

此 gif 显示了过程的前几秒以及每个 div 完成的时间:GIF

我试过了(注意 = 前面的 + 符号) document.getElementById("mini_blocks").innerHTML += '<div>'

...快了很多,它做同样的事情但替换了所有以前的 div,所以我最后只得到一个 div。这几乎是瞬间的!

我还注意到 div 中的 none 会出现,直到所有 div 都完成,我不知道为什么。

真题:

  1. 在创建 divs 时是否有什么东西使 += 方法变慢?
  2. 为什么 div 中的 none 会出现到最后?
  3. 我是网络编程新手。有没有更好的方法来做同样的事情?

而不是查找 document.getElementById("mini_blocks") 然后在循环的每次迭代中设置 .innerHTML - 尝试将值存储在全局变量中(我在这里使用 printMiniResult)和设置 .innerHTML 一次...

var printMiniResult = "";

printAllMini = function() {
    console.log("PRINTING!");
    for (var i = 0; i < docs.length; i++) {
 var object = docs[i];
 printMini(object.id, object.arrived, object.booked, object.verification, object.org, object.price, object.stax, object.pic);
 console.log(i);
    }
    document.getElementById("mini_blocks").innerHTML = printMiniResult;
    console.log("DONE!");
}

printMini = function(id, arrived, booked, verification, org, price, stax, pic) {
    if (verification != "-") {
 // So that no string is empty
 if (id == "") { id = "-"; }
 if (arrived == "") { arrived = "-"; }
 if (booked == "") { booked = "-"; }
 if (verification == "") { verification = "-"; }
 if (org == "") { org = "-"; }
 if (price == "") { price = "-"; }
 if (stax == "") { stax = "-"; }
 printMiniResult += '<div class="mini" id="\'' + id + '\'" onclick="changeInfo(\'' + arrived + '\', \'' + booked + '\', \'' + verification + '\', \'' + org + '\', \'' + price + '\', \'' + stax + '\', \'' + id + '\'), getPDF2(\'' + id + '\')"> <div class="mini_header"> <table class="mini_table"> <tr> <td align="left"> <b>Inkommen</b> </td> <td align="right"> <b>ID</b> </td> </tr> <tr> <td align="left">' + arrived + '</td> <td align="right">' + id + '</td> </tr> </table> </div> <div class="mini_img"> <img src="data:image/jpeg;base64,' + pic + '"> </div> <div class="mini_footer"> <table class="mini_table"> <tr> <td align="left"> <b>Bokförd</b> </td> <td align="right"> <b>Verifikat</b> </td> </tr> <tr> <td align="left">' + booked + '</td> <td align="right">' + verification + '</td> </tr> </table> </div> </div>';
    }
    else {
 printMiniResult += '<div class="mini" id="\'' + id + '\'" onclick="changeInfo(\'' + arrived + '\', \'' + booked + '\', \'' + verification + '\', \'' + org + '\', \'' + price + '\', \'' + stax + '\', \'' + id + '\'), getPDF2(\'' + id + '\')"> <div class="mini_header2"> <table class="mini_table"> <tr> <td align="left"> <b>Inkommen</b> </td> <td align="right"> <b>ID</b> </td> </tr> <tr> <td align="left">' + arrived + '</td> <td align="right">' + id + '</td> </tr> </table> </div> <div class="mini_img"> <img src="data:image/jpeg;base64,' + pic + '"> </div> <div class="mini_footer2"> </div> </div>';
    }
}


作为附加更改(根据 vol7ron 的回答提示),您可以使用数组,而不是字符串连接。正如 vol7ron 所说,这会更有效率。

所以你会有这样的东西......

var printMiniResult = [];

printAllMini = function() {
  ...
  document.getElementById("mini_blocks").innerHTML = printMiniResult.join("");
  ...
}

printMini = function(id, arrived, booked, verification, org, price, stax, pic) {
  ...
  printMiniResult.push(...);
  ...
}
  1. Is there something that makes the += method slow when creating divs?

是的,但不仅仅是 DIV。字符串连接很昂贵,而且通常会产生很差的性能。当字符串长度增加或执行更多操作(串联)时,您会开始注意到这种性能。

  1. Is there a reason why none of the divs shows up until the very end?

解释。

  1. I'm new to web-programming. Is there better ways to do the same thing?

您可以使用各种克隆对象的技术,或者只创建一次字符串。如果您想获得更好的 front-end 解决方案,您应该查看 Web frameworks/libraries,例如 React 或 Angular.

如何仅使用您的代码进行改进的一个示例是通过构建数组放弃循环中的字符串连接。然后您可以通过连接一个空字符串来连接数组的所有元素:(例如 ['begin','end'].join('')

1) 是的。每次 re-create 一个元素时,都会重新计算 DOM。连接长字符串也可能需要时间。

2) 先执行JavaScript,然后再渲染页面。浏览器只有一个线程来执行这些任务。

3) 是的,有更好的方法。 Create elements and append or insert 他们。这通常是更多的代码,但更快的结果。

如果很难删除字符串以创建 HTML,请使用 insertAdjacenHTML 而不是 innerHTML。它更快,因为它没有 re-create 元素。此外,如果可能,请创建一个尽可能大的 HTMLString,并只将一个字符串放入 DOM,这会显着减少 re-calculation 时间。

1: 在 javascript 中的字符串是 immutable。因此,每次您修改字符串时,您实际上是在创建字符串的副本,并将您的更改附加到它。随着字符串的增长,这可能会花费很多时间。

2:在您的 javascript 完成执行之前,浏览器不会呈现 HTML。您可以处理多个 div,然后放弃控制并使用超时继续处理。

3:不要使用大量字符串创建 HTML。我建议使用模板驱动的方法。您可能想查看 Reactjs 或 Angular。否则使用 dom 方法创建节点并将它们附加到 dom.