2

我有2000行数据如下

<div class="rr cf">
    <span>VLKN DR EXP</span>
    <span>01046</span>
    <span>VELANKANNI</span>
    <span>20:30</span>
    <span>DADAR</span>
    <span>10:00</span>
</div>

单击按钮时,我正在检查其中的文本并将每行的显示更新为blocknone。执行此操作的代码是

$('.rr').each(function(){
    this.style.display="block";
});

var nodes = $(".rr");
for(var i=0;i < nodes.length; i++) {
     // if data found
         nodes.get(i).style.display="block";
     // else
         nodes.get(i).style.display="none";
}

这似乎可能非常缓慢。我得到 chrome 警告框来杀死页面。

有任何想法吗?我可以在这里做什么优化?

4

5 回答 5

3

局部变量和循环


另一种提高循环性能的简单方法是将迭代器向 0 递减,而不是向总长度递增。根据每次迭代的复杂性,进行这个简单的更改可以节省高达 50% 的原始执行时间。

取自:http: //oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html

  • 尝试将 保存nodes.length局部变量,这样循环就不必每次都计算它。
  • 此外,nodes.get(i)如果您经常访问该数据,您可以将其存储到局部变量中以节省一些时间。
  • 如果顺序不重要,请考虑将 for 循环递减到 0
  • jQuery 的each()循环比自己循环遍历集合要慢一些。你可以看到这里有一个明显的区别。

非常简单的例子

您会在我的示例中看到,我将循环压缩为一个while循环:

var nodes = $(".rr span");
var i = nodes.length;

while(i--){ 
  if(i%2 === 0){
    nodes.get(i).style.color = "blue";}
}​

请注意,循环在每次迭代中while递减。i这样,当 时i = 0,循环将退出,因为while(0)计算结果为false


“分块”阵列


chunk() 函数旨在处理小块中的数组 (因此得名),并接受三个参数:“待办事项”列表, 处理每个项目的函数以及用于设置值的可选上下文 变量在 process() 函数中。计时器用于延迟每个项目的处理(在这种情况下为 100 毫秒,但可以根据您的具体用途随意更改)。每次通过时,数组中的第一项都会被删除并传递给 process() 函数。如果还有待处理的项目,则使用另一个计时器重复该过程

看看这里定义的Nick Zakaschunk方法,如果您需要分段运行循环以减少浏览器崩溃的机会:

function chunk(array, process, context){
    setTimeout(function(){
        var item = array.shift();
        process.call(context, item);

        if (array.length > 0){
            setTimeout(arguments.callee, 100);
        }
    }, 100);
} 

使用createDocumentFragment()


由于文档片段在内存中而不是主 DOM 树的一部分,因此将子片段附加到它不会导致页面重排(计算元素的位置和几何形状)。因此,使用文档片段通常会带来更好的性能。

所有浏览器都支持 DocumentFragment ,甚至 Internet Explorer 6,因此没有理由不使用它们。

回流是计算布局引擎格式化对象的几何形状的过程。

由于您正在迭代地更改这些元素的显示属性,因此页面必须为每次更改“重新绘制”窗口。如果您createDocumentFragment在那里使用并进行所有更改,然后将它们推送到 DOM,您将大大减少repainting必要的数量。

于 2012-10-19T19:03:26.620 回答
0

首先,延迟发生在哪里——在 jquery 代码中,还是在数据检查中?如果是 jquery,您可以尝试从 DOM 中分离数据容器元素(即包含所有 .rr div 的 html 元素),进行更改,然后重新附加它。这将停止浏览器在每次更改后重新处理 DOM。

于 2012-10-19T19:06:08.257 回答
0

我会尝试

1) 将所有这些 div 的公共父元素的显示设置为“无”

2)循环遍历div,适当设置显示

3)将父元素显示设置回块

我相信这会有所帮助,因为它让浏览器有机会聚合渲染更新,而不是在每次更改显示属性时强制它完全完成。如果不显示父节点,则所有子节点的可见性都无关紧要,因此浏览器不再需要在每个子节点中呈现更改,直到父节点再次可见。

另外,我看不到您首先循环遍历它们并将它们全部设置为阻塞,然后再次循环并将它们设置为预期值的目的。

于 2012-10-19T19:06:46.207 回答
0

不要在这里使用 jQuery,jQuery 只会在这里减慢速度。

    var elements = document.getElementsByClassName('rr'),
        len = elements.length;

    for(var i = 0; i < len; i++)
    {
        var ele = elements[i];
        if(ele.innerHTML.search(/01046/) != -1)
            ele.style.display = "none";
    }

这应该快得多。

于 2012-10-19T19:09:53.220 回答
0

我在循环大约 1500 个项目时也遇到了性能问题。

正如您可能已经猜到的那样,循环本身并不是瓶颈。问题在于您在其中执行的操作。

所以,我使用 setTimeout 迁移了负载。不是最漂亮的解决方案,但它使浏览器在更新之间做出响应。

var _timeout_ = 0;
for(var i=0;i < nodes.length; i++)
{
    setTimeout(
        (function(i)
        {
            return function()
            {
                if(stuff)
                {
                    nodes.get(i).style.display="block";
                }
                else
                {
                    nodes.get(i).style.display="none";
                }
            }
        })(i),
        _timeout_
    );
    _timeout_ += 4;
}

这将使每次更新延迟 4 毫秒,如果操作时间较长,浏览器将变得无响应。如果在您最慢的浏览器上该操作只需要 2 毫秒,您可以将其设置为 3,等等。随便玩玩。

于 2012-11-15T09:22:39.507 回答