【问题标题】:Why is this jquery so slow?为什么这个 jquery 这么慢?
【发布时间】:2011-03-03 11:06:29
【问题描述】:

我正在使用一个 jquery 插件来修复我生成的 html 表上的标题。不幸的是,插件的性能非常慢,我将其缩小到以下代码:

var $tbl = $(this);  
var $tblhfixed = $tbl.find("thead");  
$tblhfixed.find("th").each(function ()    
    $(this).css("width", $(this).width());  
});

在 ie 中有 2,000 行的表上,这大约需要 40 秒。有谁知道为什么它这么慢,更重要的是我怎样才能让它更快?我已经尝试了许多其他插件,这是唯一一个可以按我想要的方式工作的插件。感谢您的帮助

【问题讨论】:

标签: javascript jquery


【解决方案1】:

我猜你遇到了和我前段时间一样的问题。它称为“重新计算布局”之类的。

尝试将此脚本分成两个循环,如下所示:

var $tbl = $(this);
var $tblhfixed = $tbl.find("thead");
var widths = [];

// 1.
$tblhfixed.find("th").each(function ()
    widths.push($(this).width());
});

// 2.
$tblhfixed.find("th").each(function (index, element)
    $(this).css("width", widths[index]);
});

第一个将计算所有宽度。第二个会将它们应用于 TH 的

统一更新: 您可以通过将此代码放在 1. 和 2. 之间来提高性能:

$tblhfixed.hide();

并在 2 之后再次显示它。:

$tblhfixed.show();

【讨论】:

  • 这对我很有帮助,虽然我不完全明白为什么,而且我的代码运行起来确实很慢——肯定比以前快,但仍然很慢。
【解决方案2】:

罪魁祸首可能是.each

原因是当您使用.each而不是普通循环进行迭代时,每次迭代都会调用一个函数。在这种情况下,函数调用的开销非常大,因为每次迭代都必须创建一个新的调用堆栈。

为了更快地改变

$tblhfixed.find("th").each(function ()    
    $(this).css("width", $(this).width());  
});

var elms = $tblhfixed.find("th");
for(var i=0, elm;elm = elms[i];i++) {
    elm.css("width", elm.width());  
}

【讨论】:

  • 虽然是真的,但我认为 .each() 开销可以忽略不计 - 与重复调用 $(this) 相比
  • 其实 .each 开销相当大,试试看这里:jsperf.com/jquery-each-vs-for-loop/6
  • width() 也不是宇宙中最快的函数,IIRC,所以我也会缓存那个调用。
【解决方案3】:

首先,只有在需要遍历所有嵌套节点时才应该使用find()。在这里你可以使用children()

第二,每次$(this)创建新的jQuery对象实例,而你可以创建一次:

var $this = $(this);

每次$(this).width() 都会重新计算。确保您需要重新计算它。或者这样做:

var tableWidth = $this.width();

第三,根据@Martin Jespersen,每次迭代都会创建function 对象。

另外,这里根本不需要 jQuery。可以直接访问 DOM:

var tableWidth = ...; // get the table width the way you want
var thead = this.tHead;
var thRow = thead.rows[0];
for (var i = 0; i < thRow.length; ++i) {
  thRow.cells[i].style.width = tableWidth + "px";
}

【讨论】:

    【解决方案4】:

    您不应在传递给.each() 的函数中重复$(this)。包装一个元素有不小的开销,当你有 20k 个元素时这是不行的。您想在 .each() 调用中尽可能多地消除工作,或者完全消除它。

    另外,为什么要查询find() 两次,当您可以这样做时,应该会得到相同的结果:

    $ths = $('table thead th'); //or tableid, or something
    $ths.css('width', $ths.width());
    

    【讨论】:

    • 为什么将th宽度设置为table宽度?这不是 OP 的代码正在做的事情。
    【解决方案5】:

    似乎 $.width() 比原生 get(0).clientWidth 慢 99 倍,看看这个测试:http://jsperf.com/jq-width-vs-client-width

    【讨论】:

      猜你喜欢
      • 2011-01-18
      • 1970-01-01
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      • 2020-03-19
      • 2014-03-12
      • 2012-11-19
      • 2020-11-14
      相关资源
      最近更新 更多