IE8(javascript):在SELECT元素中加载大量选项的速度非常慢

IE8 (javascript): very slow to load large list of options in SELECT element

本文关键字:选项 速度 非常 加载 javascript 元素 SELECT IE8      更新时间:2023-09-26

我正在使用createElement和add方法加载带有6000个项的SELECT元素。代码如下所示,也可以在此处访问。在IE8中,加载列表大约需要16秒,而清除列表大约需要相同的时间。在IE9和Firefox中,加载时间为<2秒并且清除时间为<1秒。关于如何提高IE8的速度,有什么想法吗?

谢谢。

<script type="text/javascript">
window.onload = loadList;
function loadList() {
    clearList();
    var start = new Date().getTime();
    var o = document.getElementById("listLookupAvailableItems")
    for (var i = 0; i < 6000; i++) {
        var option = document.createElement("option");
        option.text = 'ABCDF ' + i;
        option.value = option.text;
        o.add(option, o.options[null]);
    }
    log('Load time: ' + (new Date().getTime() - start));
}
function clearList() {
    var start = new Date().getTime();
    document.getElementById("listLookupAvailableItems").options.length = 0;
    log('Clear time: ' + (new Date().getTime() - start));
    return false;
}
function log(txt) {
    document.getElementById('infoPanel').innerHTML += '</br>' + txt;
}
</script>

我的猜测是,在IE8中,特定的DOM操作非常慢。通常,在任何浏览器中,操作DOM是最慢的操作类型。为了避免这种情况,我通常会尝试找到将更改组合到一个DOM更新中的方法(例如,向表中添加6000行的HTML"批",而不是单独向表中增加6000行)。

在本例中,唯一的方法可能是将所有<option>元素创建为HTML,然后使用innerHTML将它们插入到<select>中。请参阅以下jsfiddle示例:http://jsfiddle.net/pseudosavant/bVAFF/

我没有IE8可以测试,但对我来说,即使在Firefox中(22ms vs 500ms),它也快得多。

更新

看起来它在IE中的innerHTML加载列表时不起作用,但在清除列表时起作用。不过,加载它可以使用jQuery $(o).html(html);。我更新了jsfiddle示例,它可以在IE9中工作,希望现在可以在IE8中工作。

Javascript:

$(document).ready(function(){
    loadListBatch();
});
function loadListBatch() {
    clearListBatch();
    var start = new Date().getTime();
    var o = document.getElementById("listLookupAvailableItems")
    var html = "";
    for (var i = 0; i < 6000; i++) {
        html += "<option value='"+'XYZ' + i+"'>"+'XYZ ' + i+"</option>";
    }
    // o.innerHTML = html; // Only one DOM operation, but still doesn't work in IE
    $(o).html(html); // Using jQuery to insert the HTML makes it work with IE
    console.log('Load time: ' + (new Date().getTime() - start));
}
function clearListBatch() {
    var start = new Date().getTime();
    document.getElementById("listLookupAvailableItems").innerHTML = ""; // It was already only one DOM call, but this is faster it seems.
    console.log('Clear time: ' + (new Date().getTime() - start));
    return false;
}

如果您支持IE7/IE8,则应尽量减少DOM的JavaScript操作。因此,如果要附加、插入或删除节点,通常需要尽量减少DOM操作。最好的解决方案是批量更新项目。

因此,如果您有一个选择列表,并且您正在执行JQuery.append(),那么如果在追加之前连接整个选项字符串,您将获得更好的性能。

var str = $('<option value="x">Item 1</option>' + '<option value="y">Item 2</option>');
$('#selectMenu').append(str);
//or in a loop
var array = ['orange','apple','grapes','mangoes'];
var str = '';
for (var x= 0; x < array.length; x++) {
    str = str + '<option value="' + x + '">' + x + '</option>';
}
$('#selectMenu').append(str);

此外,如果您想了解IE8执行JavaScript的速度,请运行SunSpider JS测试。火狐22和Chrome 27大约是300毫秒,IE8大约是4000毫秒。这告诉了你JS速度慢的原因。有趣的是,IE10现在不到200毫秒。http://www.webkit.org/perf/sunspider/sunspider.html

我也遇到过类似的情况。

我有一组1700+的输入,所以我提供了一个"过滤器"选项,该选项将复制选择并应用基于复制列表之外的过滤器。(它"打开"了一个对话框,将下拉列表框扩展到几乎与屏幕80%一样大的列表)

复制在其他浏览器中效果不明显,但在IE中需要8-15秒。

该解决方案基于之前的答案,也基于这篇文章(学习向DOM添加元素的缓慢(和快速)方法),是将所有项添加到HTL字符串中,然后将其分配给一个新对象的innerHTML,该对象还不是DOM的一部分。最后,用新的对象替换DOM中的对象。

这显然减少了浏览器执行的"回流"操作的数量,而这很可能是性能如此缓慢的罪魁祸首。

在实现这种风格之前的一些测试是在不向列表中添加选项的情况下运行完整的for循环,在这样的测试中,代码执行得非常快,很明显selectElement.add(optionElement)是缓慢的部分。

以下是我的函数结束的示例:

    function fillselector(IdSelect){
        var selector = document.getElementById(IdSelect);
        if( !selector ){
            alert('Original select element not found.');
            return;
        }
        var lista = document.getElementById('selectFilter_lista');
        if( !lista ){
            alert('Copied list element not found.');
            return;
        }
        var filterText = noSpecialChars(document.getElementById('selectFilter_text').value);
        var options =''
        for (var i = 0; i < selector.length; i++){
            if (filterText == '' || noSpecialChars(selector[i].text).indexOf(filterText) != -1 ){
                //Commented code works but is painfuly slow on IE
                //var option = document.createElement("option");
                //option.value = selector[i].value;
                //option.text = selector[i].text;
                //lista.add(option);
                options += '<option value="'+selector[i].value+'">'+selector[i].text+'</option>';
            }
        }
        var newList = document.createElement('select');
        newList.id='selectFilter_list';
        newList.className='selectFilter_list';
        newList.size = 20;
        newList.ondblclick= function(){closeselector(IdSelect, true);}
        newList.innerHTML = options;
        newList.value = selector.value;
        var listParent = lista.parentElement; //<div> that only contains the <select>
        listParent.removeChild(lista);
        listParent.appendChild(newList);
    }