如何优化这个jquery循环的执行时间

How can I optimize execution time of this jquery loop?

本文关键字:jquery 循环 执行时间 何优化 优化      更新时间:2023-09-26

我有一个循环,它通过类为"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.我执行循环的顺序并不重要。第一个循环总是比其他循环慢得多,也是在最后执行该循环时。

// 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';
});

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

我想说的是,最后两个循环加起来并不等于第一个循环的功能,所以第一个循环比其他两个循环的加起来慢也就不足为奇了。

你应该试试这样的东西:

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而且差别似乎很小。

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];
    });
});

假设父宽度的计算不是动态的(子宽度的大小不会影响父宽度),并且宽度是恒定的(big if’s)。

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

在您的第一个示例中

$('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);
});

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

var width = $(this).parent().width();-你调用这个,浏览器会强制你获得所选元素的真实尺寸。$(this).css('width', 100);-这会导致浏览器回流文档。所以您运行此行,浏览器必须重新计算页面的一部分。

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

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

要使.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

好吧,这里有另一个选择:

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

如果你使用怎么办

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

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