在 DOM 中创建 >1000 个元素时 MSEdge 超级慢

MSEdge super slow when creating >1000 elements in DOM

几乎所有其他浏览器都能立即通过此 JS,请参阅下面的基准测试

它仅在函数中的这段代码上变慢(其余的立即运行),这太简单了,让我很困惑我能做些什么来修复它。

我无法在 JSFiddle 中重现,这里是等效代码 https://jsfiddle.net/5ax7mshz/。我可以通过 performance.now() 看到这是我们应用程序中唯一减慢速度的代码,它是一个纯 JS+JQ 应用程序,这里没有其他变量……不知何故它在我们的应用程序中花费了 600 倍的时间fiddle 中的应用程序。在这里我已经无计可施了。

谢谢大家!

var options = "";
for (var i = 0; i < data.Vendor.length; i++) {
    options += "<option value='" + data.Vendor[i].VendorID + "'>" + data.Vendor[i].Name + "</option>";
}
$el.append(options);

实际基准值

平均边缘基准(不幸的是,到目前为止尝试这里的一些解决方案仍然产生相似的值)

Chrome如果你想笑点

Aaa 和 Firefox 总共需要 46 毫秒

您使用的append是jQuery吗?

我在这台机器上没有 Edge,但我有 IE,所以我将使用它作为合理的等效项。我尝试了几个 4000 select-option 构建:

  1. 字符串连接后跟单个 jQuery append
  2. jQuery append 每个条目
  3. appendChild 每个元素(没有 jQuery)
  4. new Option(...添加到select.options(没有jQuery)

我使用的时间

console.time('build');
build();
console.timeEnd('build');

结果,两次运行 - 最快时间(毫秒):

IE11 805 2120 605 6033
FF80  48  190  26   21
CR84  95  342  52  214

有 4000 个元素,这是与你的 list2 的比较,而第一个时间数字应该与你的结果相匹配(尽管请注意我为每个条目编了 value/text,因为我无权访问你的列表).注意 Chrome 明显比你的慢(95 vs 32 - 3x),而 IE 明显更快(805 vs 2117 - 26x)。对于我的 Chrome 进程,我有许多打开的选项卡,但还有一个更新在等待,对于我的 IE 进程,我没有打开其他任何东西,但它也与 Edge 不完全相同(假设您没有使用 Webkit Edge -如果你是,那么它是一个非常不同的引擎)

基于 jQuery 的构建都表现不佳。这不是真正的公平竞争,因为此方法必须解析字符串并将其解释为 HTML。 Build 4 在除 FireFox 之外的所有方面都表现不佳。所以,看起来 vanilla javascript 和 appendChild 是最好的方法。

将其映射回您的数据(可能 有进一步的对象访问延迟):

function build(data, select) {
  var n=data.Vendor.length;
  for (var i=0; i<n; i++) {
    var item=data.Vendor[i];
    var opt=document.createElement("option");
    opt.value=item.VendorID;
    opt.innerText=item.Name;
    select.appendChild(opt);
  }
}
// Call egs:
// build(data, document.getElementById("itemList"));
// build(data, document.forms[0].itemSelect);

最终这样做是为了至少使总时间达到 5-7 秒(5000-7000 毫秒)而不是 28 秒,即 'ok' 因为这只会影响几个客户端,其余使用 Chrome (50 毫秒)和 FF(40 毫秒)和 IE11+(300 毫秒)

document.getElementById("vendor").innerHTML = "";
var i = 0;
var loop_num = 0;
var vendorCount = data.Vendor.length;
var vendorPiece;
var k = 0;
var options = [];
if (isEdge) {
  //add optgroups to select
  var num_selects = Math.ceil(vendorCount / 1000); //say, 3 for 2323
  for (var jj = 1; jj <= num_selects; jj++) {
    var optgroup = document.createElement("optgroup");
    optgroup.label = "";
    optgroup.id = "vendor" + jj;
    document.getElementById("vendor").appendChild(optgroup);
    if (jj == 1) {
      var blankopt = document.createElement("option");
      blankopt.value = "";
      blankopt.text = "";
      document.getElementById("vendor" + jj).appendChild(blankopt);
    }
  }
} else {
  var blankopt = document.createElement("option");
  blankopt.value = "";
  blankopt.text = "";
  document.getElementById("vendor").appendChild(blankopt);
}
while (i < vendorCount) {
  var pieceEndIndex =
    Math.min(1000, vendorCount - i) == 1000 ? i + 1000 : vendorCount;
  k = 0;
  options = [];
  vendorPiece = data.Vendor.slice(i, pieceEndIndex);
  for (var j = 0; j < vendorPiece.length; j++) {
    var vendor = vendorPiece[j];
    options[k++] = "<option value='";
    options[k++] = vendor.VendorID;
    options[k++] = "'>";
    options[k++] = vendor.Name;
    options[k++] = "</option>";
  }
  var vendor_id = !isEdge ? "vendor" : "vendor" + (loop_num + 1);
  document.getElementById(vendor_id).innerHTML += options.join("");
  i += vendorPiece.length;
  loop_num++;
}