如何优化此jquery循环的执行时间?

时间:2012-08-29 08:45:54

标签: javascript jquery performance execution-time

我有一个循环通过类'GridCell'的表格cel中的所有div。 在某些情况下,当调整网格或列的大小时,需要这样做。

我扩展了行数和列数,以查看更多的时差,现在循环大约为750毫秒。

但我不明白的是,“只是循环的一部分”要快得多。请参阅以下三个循环。第一个是缓慢的。仅执行第一个循环的一部分的第二个和第三个循环非常快。

//Around 750 ms
$('table.Grid tbody td.GridCell > div').each(function() {
    var width = $(this).parent().width();
    $(this).css('width', width - 3);
});

//Around 60 ms
$('table.Grid tbody td.GridCell > div').each(function() {
    var width = $(this).parent().width();
});

//Around 15 ms
$('table.Grid tbody td.GridCell > div').each(function() {
    $(this).css('width', 100);
});

所以一行,只有60或15毫秒,但两者一起是750.这有什么区别?

P.S。我执行循环的顺序无关紧要。第一个循环总是比其他循环慢得多,也就是最后执行该循环时。

9 个答案:

答案 0 :(得分:2)

在第一个循环中,您正在计算计算的宽度,然后将其应用于每次迭代的另一个元素。在第二个循环中,您所做的只是计算宽度,并将其分配给变量。在第三个循环中,您只是应用静态内联样式。

我所说的是最后两个循环组合起来并不等于第一个循环的功能,所以第一个循环比其他两个循环慢,这并不奇怪。

你应该尝试类似的东西:

var $divs = $('table.Grid tbody td.GridCell > div'),
    m = [];

// case 1
$divs.each(function() {
    var width = $(this).parent().width();
    $(this).css('width', width - 3);
});

// case 2
$divs.each(function() {
    m.push( $(this).parent().width() );
}).each(function(i) {
    $(this).css('width', m[i] - 3);
});

我在这里做了一个简单的性能测试:http://jsperf.com/tablewidth,差异似乎非常小。

答案 1 :(得分:2)

// collect the widths from the first row only
var widths = $('table.Grid tbody tr:first-child td.GridCell').map(function(idx) {
  return $(this).width() - 3;

  // or use:
  // return this.clientWidth - 3;
  // if you're not targeting IE <= 7
});

// apply the widths to each div
$('table.Grid tbody td.GridCell > div').each(function(idx) {
  this.style.width = widths[idx % widths.length] + 'px';
});

答案 2 :(得分:1)

var $rows = $('table.Grid tbody').children('tr');

// we only need the widths from the first row
var widths = $rows.first().children('td').map(function() {
    return $(this).width() - 3;
}).get();

// process each row individually
$rows.each(function() {
    $('td.gridCell > div', this).css('width', function(i) {
         return widths[i];
    });
});

答案 3 :(得分:0)

在你的第一个例子中

$('table.Grid tbody td.GridCell > div').each(function() {
    var width = $(this).parent().width();
    $(this).css('width', width - 3);
});

您正在评估$(this)两次。试着写一下

$('table.Grid tbody td.GridCell > div').each(function() {
    var $this = $(this);
    var width = $this.parent().width();
    $this.css('width', width - 3);
});

甚至更好(编辑:不确定)也尝试使用each()方法传递的当前元素

$('table.Grid tbody td.GridCell > div').each(function(i, el) {
    var $this = $(el);
    var width = $this.parent().width();
    $this.css('width', width - 3);
});

答案 4 :(得分:0)

如果你使用

怎么办?
$('table.Grid tbody td.GridCell > div').each(function(i,domEle) {
    $(domEle).css('width', $(domEle).parent().width() - 3);
});

并尝试在jQuery中使用优化选择器

答案 5 :(得分:0)

假设父宽度的计算不是动态的(子剂量的大小调整会影响父级),宽度是恒定的(大的,如果是)。

var width = $(this).parent().width();

$('table.Grid tbody td.GridCell > div').each(function() {
    $(this).css('width', width - 3);
});

答案 6 :(得分:0)

我很难说出确切的细节,但我理解这个问题:

var width = $(this).parent().width(); - 你打电话给这个,浏览器被迫让你获得所选元素的真实尺寸。 $(this).css('width', 100); - 这会导致浏览器重排文档。所以你运行这一行,浏览器必须重新计算页面的一部分。

为什么第一个比其他两个循环慢?我看到它就像你只做var width = $(this).parent().width();时它可以计算所有宽度一次并从缓存中给出它们。 现在当你只做这行$(this).css('width', 100);时 - 浏览器可以等待直到执行脚本。并立即重绘所有更新元素。 但是,当您执行第一个循环时,强制浏览器计算宽度,而不是更新某个元素。维度缓存已损坏。现在你又想要获得宽度,浏览器必须重绘页面。因此,每当它只能执行一次时,它会将对页重绘为其他两个循环。

答案 7 :(得分:0)

这不一定是JS问题! 忘记循环,你根本不需要使用JS / jQuery来实现所需的功能。 / p>

要使.GridCell的子div占用所有可用宽度减去3px ,您可以使用以下CSS规则:

.GridCell>div {
  width:auto;             /*take up all available width (for block elements)*/
  margin:0 1.5px;         /*add a 1.5px buffer on both sides of the div*/
}

如果你想要真的很花哨并且不关心浏览器兼容性矩阵有点差,你可以依赖CSS3 calc()

.GridCell>div {
  width:calc(100% - 3px); /*look up vendor-specific prefixes of the property
                            if you want for this to work on more browsers*/
  margin: 0 auto;         /*now that the width is calculated correctly above,
                            center the div. Or don't!*/
}

Et voila

答案 8 :(得分:0)

好的,这是另一种选择:

$('table.Grid tbody td.GridCell > div').css('width', function() {
    return $(this.parentNode).width() - 3;
});