jQuery width() method performance

独自空忆成欢 提交于 2019-12-18 09:07:04

问题


I'm a jQuery noob trying to track down a performance issue that we're having with large tables. We have a homegrown table widget which, among other things, sets the column widths to the max of the header width or the rows width.

With a table of 10 rows by 500 columns, this can take almost 40 seconds (!) which seems excessive given that the table can be rendered in under a second.

Here's the whole function:

  var dataTable = this._div.find('.data-table');
  var headerTable = this._div.find('.data-header-table');
  if (dataTable.length === 0 || headerTable.length === 0) {
    return;
  }
  dataTable = dataTable[0];
  headerTable = headerTable[0];

  if (dataTable.rows.length === 0) {
    return;
  }

  var dataTr = dataTable.rows[0];
  var headerTr = headerTable.rows[headerTable.rows.length - 1];

  var marginColumnWidths =
    $(dataTr.cells[0]).outerWidth(true) +
    $(dataTr.cells[1]).outerWidth(true) +
    $(dataTr.cells[2]).outerWidth(true) -
    DOM.getHPaddings($(headerTr.cells[0])) + 1;

  $(headerTable)
    .find('> tbody > tr > td:first-child')
    .width('1%')
    .children()
      .first()
      .width(marginColumnWidths);

  for (var i = 1; i < headerTr.cells.length; i++) {
    var headerTd = $(headerTr.cells[i]);
    var dataTd = $(dataTr.cells[i + 2]);
    var commonWidth = Math.max(
      Math.min(headerTd.width(), 100),
      dataTd.width()
    );
    headerTd.width('1%').find('> div').width(commonWidth);
    dataTd.children().first().width(commonWidth);
  }

If I replace

    var commonWidth = Math.max(
      Math.min(headerTd.width(), 100),
      dataTd.width()
    );

with a constant

    var commonWidth = 100;

the execution time drops from 38 seconds to under a second, indicating that the issue is on reading/calculating the current widths as opposed to setting the new width. From the profiling/sampling that I've done, it appears that jQuery is spending an inordinate amount of time messing around with CSS calculations.

Can anyone recommend a more efficient way to do this?

EDIT:

I've tried both css("width") and outerWidth() without any significant changes in performance. We were using jQuery 1.7.2, but upgrading to 1.8.1 didn't change performance significantly.


回答1:


Use .css("width") instead of .width(), changes were made to the .width() method that make it perform slower. Read this for more information: http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/

var commonWidth = Math.max(
  Math.min(parseFloat(headerTd.css("width")), 100),
  dataTd.width()
);



回答2:


As I know - .width() is taking real width(not always one set in css) and to get it - browser must calculate it (forced page redraw and width calculation itself). Now, you are setting width, browser need to redraw everything. It may do that with slight delay, but in next step you are taking width again - browser MUST redraw page to get a real width. Count widths first, than - in another loop, set calculated values. I think this should help

EDIT:

Tested this comparing to Kelvin B approach. Difference is not significant. Looks like the best is when css("width") is used. Here are tests: Hm. Tested this. Comparing with approach I suggested. Appeared that difference is not big. Here are test: width one loop, css width one loop, css two loops, width two loops. In result - almost no difference. The slowest - "width one loop". Fastest - one of those with css. Different from time to time for me.

Note: four different tests with on case because looks like js perf does not clear html state between test cases.

Not sure what could be done in your case, but what I see strange is .width('1%') you are using. For me it looks like you do not need it, so maybe you can try removing it.




回答3:


if you do .width (and also .css("width")) on table cell (or headers) of very large tables, it takes an awful lot of time FOR HIDDEN ELEMENTS !!!, and is very fast for visible elements. The reason is, if the element is hidden, the browser, being nice and efficient, has not made any effort to find out what the width would be, if the element were visible. But jQuery's .width, apparently, for hidden elements, returns what the width would be, if it were visible, instead of just returning zero (it's hidden alright). For large tables, that means that the browser has to render the whole table again. If the table is really large it can take over a second. And if you then do that for multiple hidden columns (just measuring their widths) your page becomes useless.

so do not measure width of hidden elements unless you REALLY need to know.

relevant link, repeating what I just said (and more): here



来源:https://stackoverflow.com/questions/12414150/jquery-width-method-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!