在 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);
实际基准值
平均边缘基准(不幸的是,到目前为止尝试这里的一些解决方案仍然产生相似的值)
- 总共 28155 毫秒
- 6968 毫秒列表 1(2232 项)
- 21179 毫秒列表 2(4016 项)
- 7.6 毫秒列表 3(10 项)
Chrome如果你想笑点
- 总计 55.07 毫秒
- 21.09 毫秒列表 1(2232 项)
- 32.18 毫秒 list2(4016 项)
- 1.79 毫秒列表 3(10 项)
Aaa 和 Firefox 总共需要 46 毫秒
您使用的append
是jQuery吗?
我在这台机器上没有 Edge,但我有 IE,所以我将使用它作为合理的等效项。我尝试了几个 4000 select-option 构建:
- 字符串连接后跟单个 jQuery
append
- jQuery
append
每个条目
appendChild
每个元素(没有 jQuery)
- 将
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++;
}
几乎所有其他浏览器都能立即通过此 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);
实际基准值
平均边缘基准(不幸的是,到目前为止尝试这里的一些解决方案仍然产生相似的值)
- 总共 28155 毫秒
- 6968 毫秒列表 1(2232 项)
- 21179 毫秒列表 2(4016 项)
- 7.6 毫秒列表 3(10 项)
Chrome如果你想笑点
- 总计 55.07 毫秒
- 21.09 毫秒列表 1(2232 项)
- 32.18 毫秒 list2(4016 项)
- 1.79 毫秒列表 3(10 项)
Aaa 和 Firefox 总共需要 46 毫秒
您使用的append
是jQuery吗?
我在这台机器上没有 Edge,但我有 IE,所以我将使用它作为合理的等效项。我尝试了几个 4000 select-option 构建:
- 字符串连接后跟单个 jQuery
append
- jQuery
append
每个条目 appendChild
每个元素(没有 jQuery)- 将
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++;
}