在IE和FF中慢执行js

时间:2012-02-02 23:02:26

标签: javascript json performance

我有这个函数运行返回的json数据。它的速度非常快,但IE和FF速度很慢。关于如何改进这个的建议?返回的数据大约是15个对象。这会在顶部创建一堆锚点,每个标题下都有列表。

function list_response(jsonData) {
    "use strict";
    var lists = document.getElementById("lists"), anchors = document.getElementById("anchors"), jItems = jsonData.items;
    jItems.sort(function (a, b) {
            return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
            });
    for (var i = 0; i < jItems.length; i++) {
        var pList = jItems[i], str = "", ank = "";
        str += '<span class="backtotop">[ <a href="#">Back to top</a> ]</span><br /><br /><br /><li class="title nodot"><a class="pHeader" name="' + pList.name + '"><h2>' + pList.name + '</h2></a></li>';
        ank += '<a class="pHeader" href="#' + pList.name + '">' + pList.name + '</a>&nbsp; ';
        lists.innerHTML += str;
        anchors.innerHTML += ank;

        for (var j = 0; j < jsonData.items[i]["videos"].length; j++) {
            var vList = jsonData.items[i]["videos"][j];
            var strs = "";
            strs += '<li class="nodot"><a href="https://www.site.org/videos/Video_Player.page?bctid=' + vList.id + '">' + vList.name + '</a></li>';
            lists.innerHTML += strs;
        }
    }
}

6 个答案:

答案 0 :(得分:4)

以下是代码的一个版本,它结合了以下性能增强功能:

  1. 仅在循环结束时添加一次innerHTML。您希望尽可能多地避免这样做,因为每次添加该项时,它都会导致对该项中所有HTML的完整重新分析。这最大限度地减少了与DOM的事务数量,这可能是整个例程中最慢的部分。这个改进版本大大减少了DOM事务的数量。如果jItems.length20且平均视频数为5,则会将DOM事务数量减少到DOM事务数量的1/50。
  2. 使用.push()将字符串数据累积到数组中,并在最后执行.join(),而不是每次都添加到字符串的末尾。 JS引擎通常可以比连接每个片段更有效地连接大量字符串。
  3. 当将字符串数据累积到数组中时,不再需要在每个循环或子循环上初始化临时数据。
  4. 而不是获取pList,然后有四个对pList.name的引用,只需获取一次名称值并直接使用它。
  5. 在循环中缓存jItems[i]因为它引用了几个地方而不是每次重新计算它。
  6. 只计算一次for循环的len变量并与之进行比较,而不是在每次迭代时重新计算它。
  7. 在外循环中缓存jItems[i]["videos"]一次,而不是每次在内循环中重做它。
  8. 如果jsonData.items中有大量项目,则排序算法效率不高,因为每次比较都必须重新计算每个名称的小写版本。您可以在一次传递中预编译所有小写版本(每个项目一次),然后在排序算法中使用它们,而不是每次比较两个项目时都必须重做它们。
  9. 这些更改导致此代码:

    function list_response(jsonData) {
        "use strict";
        var lists = document.getElementById("lists"), anchors = document.getElementById("anchors"), jItems = jsonData.items;
        var results = [], anks = [], vList, pListName, item, videoItem;
        // precache all lower case versions to make sorting faster
        var i, iLen = jItems.length, j, jLen;
        for (var i = 0; i < iLen; i++) {
            jItems[i].nameLower = jItems[i].name.toLowerCase();
        }
        jItems.sort(function (a, b) {
            return a.nameLower.localeCompare(b.nameLower);
        });
        for (i = 0; i < iLen; i++) {
            item = jItems[i];                   // cache for use in loops
            videoItem = item["videos"];      // cache for use in loops
            pListName = item.name;            // cache for use in multiple places
            results.push('<span class="backtotop">[ <a href="#">Back to top</a> ]</span><br /><br /><br /><li class="title nodot"><a class="pHeader" name="' + pListName + '"><h2>' + pListName + '</h2></a></li>');
            anks.push('<a class="pHeader" href="#' + pListName + '">' + pListName + '</a>&nbsp; ');
    
            for (j = 0, jLen = videoItem.length; j < jLen; j++) {
                vList = videoItem[j];
                results.push('<li class="nodot"><a href="https://www.site.org/videos/Video_Player.page?bctid=' + vList.id + '">' + vList.name + '</a></li>');
            }
        }
        lists.innerHTML += results.join("");
        anchors.innerHTML += anks.join("");
    }
    

答案 1 :(得分:2)

您可以尝试长度缓存 - 例如,创建变量l = jItems.length,并在for循环的条件下使用它,而不是每次都获取length属性 - 具体取决于实现查找数组的长度通常会有一些开销,所以如果你有一个大数组,这个差异就会很明显。

此外,创建临时变量以保持strank字符串变大,然后只将它们放在最后的innerHTML右边。

答案 2 :(得分:1)

你不应该使用字符串和innerHTML来构建HTML。你应该使用DOM。

答案 3 :(得分:1)

老技巧,不太确定它是否相关,但

var builder = [];
builder.push('foo');
builder.push('bar');
builder.push('baz');
var str = builder.join('')

在IE中比

快得多
var str = '';
str += 'foo';
str += 'bar';
str += 'baz';

答案 4 :(得分:0)

var strHTML = "";
var ankHTML = "";

for (var i=0; i < jItems.length; i++){
  ...    
  strHTML += str;
  ankHTML += ank;
  ...
}
lists.innerHTML = strHTML ;
anchors.innerHTML = ankHTML ;

答案 5 :(得分:0)

这里的主要性能瓶颈无疑是您使用innerHTML的方式。

el.innerHTML += aString;当然等同于el.innerHTML = el.innerHTML + aString;

这意味着对于每次调用,DOM将被序列化为HTML字符串,然后反序列化为有效的DOM。这是很多不必要的工作。

相反,要么:

(a)预先构建所有HTML并为每个元素分配innerHTML一次。

(b)将元素或文档片段附加到父节点。