4

我有一个循环,它遍历表 cel 中的所有 div,类为“GridCell”。在某些情况下,当调整网格或列的大小时,这需要发生。

我扩展了行数和列数,以查看更多时间差异,现在循环大约为 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。这有什么区别?

ps 执行循环的顺序无关紧要。第一个循环总是比其他循环慢很多,最后执行该循环时也是如此。

4

9 回答 9

2

In the first loop, you are calculating a computed width, then applying that to another element for each iteration. In the second loop, all you do is computing the width, and assigning it to a variable. And in the third loop, you are simply applying static inline styles.

What I’m saying is that the last two loops combined does not equal the functionality of the first, so it’s no surprise that the first one slower than the other two combined.

You should try something like:

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

I made a simple perf test here: http://jsperf.com/tablewidth and the difference seems to be very small.

于 2012-08-29T08:53:04.920 回答
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';
});
于 2012-08-29T09:30:21.287 回答
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];
    });
});
于 2012-08-29T09:15:05.543 回答
0

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

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

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

于 2012-08-29T09:07:58.193 回答
0

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

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

$('table.Grid tbody td.GridCell > div').each(function() {
    $(this).css('width', width - 3);
});
于 2012-08-29T08:55:41.683 回答
0

in your first example

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

you're evaluating $(this) twice. try to write instead

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

or even better (edit: not sure) try also to use the current element passed along the each() method

$('table.Grid tbody td.GridCell > div').each(function(i, el) {
    var $this = $(el);
    var width = $this.parent().width();
    $this.css('width', width - 3);
});
于 2012-08-29T08:52:55.367 回答
0

what if you use

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

And also try to use optimize selector in jQuery

于 2012-08-29T08:53:16.997 回答
0

好的,这是另一种选择:

$('table.Grid tbody td.GridCell > div').css('width', function() {
    return $(this.parentNode).width() - 3;
});
于 2012-08-29T09:46:27.703 回答
0

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

要使子 div.GridCell占用所有可用宽度 - 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!*/
}

于 2012-08-29T09:24:01.577 回答