开发者

Optimizing Jquery iteration through table columns comparing with existing row

I'm trying to write a function to add color to a table based on a reference which is one of the top rows of the table. There are several questions in SO mentioning row based iteration but not so much about column.

The structure of the table is something like:

<table id="data">
    <tr>
        <th rowspan="2">Name</th>
        <th rowspan="2">Selection<开发者_Go百科;/th>
        <th rowspan="2">Title</th>
        <th rowspan="2">Info1</th>
        <th rowspan="2">Info2</th>
        <th colspan="10">Data</th>
    </tr>
    <tr>
        <th>001</th>
        <th>002</th>
        <th>003</th>
        <th>004</th>
        <th>005</th>
        <th>006</th>
        <th>007</th>
        <th>008</th>
        <th>009</th>
        <th>010</th>
    </tr>
    <tr id="ref_control">
        <td></td>
        <td>RefName</td>
        <td></td>
        <td></td>
        <td></td>
        <td>A</td>
        <td>B</td>
        <td>J</td>
        <td>L</td>
        <td>Z</td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
    </tr>
    <tr>
        <td><input type="checkbox" name="checkbox"/></td>
        <td>Entity 1</td>
        <td>Info...</td>
        <td>More info...</td>
        <td>Even more...</td>
        <td>A</td>
        <td>T</td>
        <td>M</td>
        <td>L</td>
        <td>Z</td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>2</td>
        <td>5</td>
    </tr>
    (...)
</table>

In addition I'm using JQuery and the JQuery column cell select plugin to perform the mentioned task.

The Javascript code looks like this:

$(document).ready(function() {
    // Colorize table based on matches
    // Number of Data entries - Count on the reference (2nd row)
    // and only 5th column onwards (index starts at 0)
    var datasize = $("#data tr:eq(2) td:gt(4)").length;

    // Start with column 6 (index starts at 1)
    var begin = 6;

    for (var i = begin; i < begin + datasize; ++i) {
        var curCol = $("#data td").nthCol(i);
        var ref = curCol.eq(0).text();
        curCol.not(curCol.eq(0)).each(function() {
            var data = $(this);
            if (data.text() == '') {
                data.addClass("black");
            } else if (data.text() != ref) {
                data.addClass("color");
            }
        });
    }
});

A working example can be visualized here. In the example the table has only 9 rows and 10 data columns. The actual page I'm trying to optimize has 20 rows and 90 data columns.

Using the mentioned Javascript extensions/plugins the big sized table poses no threat to the Google Chrome browser taking a few seconds to load, however Opera, Firefox and Internet Explorer have a hard time running the function or end up asking for user interaction to stop the script from running.

So my question is aimed at both alternatives to the column select plugin or ways to optimize the code such that I don't kill almost all browsers except Google Chrome.

Edit: Changes according the the two comments from @Pointy


You can easily get 10x faster code if you want. Just save references once and go row by row instead of column by column. It doesn't become more complicated yet it performs much better. The reason is that your plug-in hides the abstraction that your table is made of rows that are made of columns. And not the other way around. Emulating the second version can be costy as you noticed in this example.

You may also use DOM properties instead of jQuery methods. They are really straightforward.

// get text (modern browsers || IE <= 8)
var text = elem.textContent || elem.innerText;
// set class
elem.className = "black";

your final code will be something like:

var refcells = $("#data tr:eq(2) td:gt(4)");
var datasize = refcells.length;
// Start with column 5
var begin = 5;
var refs = [];
var i = begin;
refcells.each(function () {
  refs[i++] = $(this).text();
});

$("#data tr:gt(2)").each(function () {
  var cells = $("td", this);
  for (var i = begin; i < begin + datasize; i++) {
    var elem = cells[i];
    var text = elem.textContent || elem.innerText;
    if (!text) {
      elem.className = "black";
    } else if (text != refs[i]) {
      elem.className = "color";
    }
  }
});


Doing what you're doing is going to be very computationally intensive. Since your table layout seems pretty regular, I'd just completely ditch that nthCol() thing (for this page anyway) and do your work by iterating over the table once:

  1. Grab the "key" row first, and save it
  2. Loop through each relevant <tr>, and for each one get the <td> elements and iterate over them as a raw node list, or as a jQuery list. Either way it should be a lot faster.
  3. In the second loop, you'll do the same logic you've got (although I'd use addClass() and removeClass()), referring back to the saved "key" row for each cell.

In your current loop, you're re-building the jQuery object of every <td> in the table for each column, and then you're doing that nthCol() work! That's a lot of work to do if you do it once, so repeating that for every single column is going to really drag that CPU down. (On IE6 - especially with all those "class" changes - I bet it's almost unbearably slow.)

edit — I looked over that code (for the plugin), and while it looks like it was competently implemented it doesn't have any "magic tricks". All it does is iterate through all the table cells you give it and checks whether or not each cell is in fact in the "nth" column. Thus, your iteration will perform that test on every cell in the table for every column you care about. In your 90x20 table, that'd be about 85 iterations through all 1800 cells. And that's before you do your work!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜