0

I have a for loop that take too long to execute large amount of data:

for (var itm = 0; itm < itmCount; itm++) {

    var curObj = $('[aria-describedby=' + gridName + '_' + columnNames[itm].name + ']');

    var thisCell = $('#' + gridName + '_' + columnNames[itm].name + ' div');
    $('#widthTest').html(thisCell.text()).css({
    'font-family': thisCell.css('font-family'),
    'font-size': thisCell.css('font-size'),
    'font-weight': thisCell.css('font-weight')
    });
    var maxWidth = Width = $('#widthTest').elementRealWidth() + 17;

    var itm2Count = curObj.length;
            // Loop through Rows
            for (var itm2 = 0; itm2 < itm2Count; itm2++) {

            var thisCell = $(curObj[itm2]);

            $('#widthTest').html(thisCell.html()).css({
            'font-family': thisCell.css('font-family'),
            'font-size': thisCell.css('font-size'),
            'font-weight': thisCell.css('font-weight')
            });

            thisWidth = $('#widthTest').elementRealWidth();
            if (thisWidth > maxWidth) {maxWidth = thisWidth+10;}
            }

    $('#' + gridName + ' .jqgfirstrow td:eq(' + itm + '), #' + gridName + '_' + columnNames[itm].name).width(maxWidth).css('min-width', maxWidth+17);
    $('#' + gridName + ' .jqgfirstrow td:eq(' + 0 + '), #' + gridName + '_' + columnNames[0].name).width('30').css('min-width', '30px');

I get this issue from firefox:

A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.

and the Chrome kills the page. Any idea?

UPDATE:

Here is my code after doing chunk:

var itmCount = columnNames.length;

    var numOfElements = itmCount;
    var elementsPerChunk = 50;
    var numOfChunks = numOfElements / elementsPerChunk; //divide it into chunks

    for (var x = 0; x < numOfChunks; x++) {
        setTimeout(function() {
        for (var y = 0; y < elementsPerChunk; y++) {


                var curObj = $('[aria-describedby=' + gridName + '_' + columnNames[elementsPerChunk].name + ']');

                var thisCell = $('#' + gridName + '_' + columnNames[elementsPerChunk].name + ' div');
                $('#widthTest').html(thisCell.text()).css({
                'font-family': thisCell.css('font-family'),
                'font-size': thisCell.css('font-size'),
                'font-weight': thisCell.css('font-weight')
                });
                var maxWidth = Width = $('#widthTest').elementRealWidth() + 17;

                var itm2Count = curObj.length;
                        // Loop through Rows
                        for (var itm2 = 0; itm2 < itm2Count; itm2++) {

                        var thisCell = $(curObj[itm2]);

                        $('#widthTest').html(thisCell.html()).css({
                        'font-family': thisCell.css('font-family'),
                        'font-size': thisCell.css('font-size'),
                        'font-weight': thisCell.css('font-weight')
                        });

                        thisWidth = $('#widthTest').elementRealWidth();
                        if (thisWidth > maxWidth) {maxWidth = thisWidth+10;}
                        }

                $('#' + gridName + ' .jqgfirstrow td:eq(' + elementsPerChunk + '), #' + gridName + '_' + columnNames[elementsPerChunk].name).width(maxWidth).css('min-width', maxWidth+17);
                $('#' + gridName + ' .jqgfirstrow td:eq(' + 0 + '), #' + gridName + '_' + columnNames[0].name).width('30').css('min-width', '30px');
                //grid.setRowData ( iids[itm], false, {height: 30} );

                }
        }, 0);
        }
amanda chaw
  • 137
  • 2
  • 14
  • How big is `itmCount`? you might have to use `setTimeout` ever so often to let the event loop continue – Miguel Mota Nov 29 '14 at 23:32
  • 1
    What your code is doing is basically torturing the browser. You're forcing it to re-flow the layout over and over and over again. What is it that you're trying to achieve? – Pointy Nov 29 '14 at 23:35
  • @Moogs I put setTimeout, but it just made a delay and the function didn't execute correctly. Can you tell me where should I put setTimeout and how? – amanda chaw Nov 29 '14 at 23:35
  • @Pointy I have a jqgrid and I try to resize the cells based of the content of each cell – amanda chaw Nov 29 '14 at 23:36
  • 1
    What I mean is, what is your overall goal in doing that? There's no way to do what you're doing without it being horribly slow, but there might be a better way to achieve your goal. – Pointy Nov 29 '14 at 23:43
  • Probably you should describe the goal of the script. What should it do? I'm sure that you goes in wrong direction and one could archive the same goals in another way. By the way want is `elementRealWidth()` method? – Oleg Nov 30 '14 at 00:08
  • @Oleg The elementRealWidth() is: $.fn.elementRealWidth = function () { $clone = this.clone() .css("visibility","hidden") .appendTo($('body')); var $width = $clone.outerWidth(); $clone.remove(); return $width; }; I used that for the modal that have hidden element that doesn't show real width. – amanda chaw Nov 30 '14 at 00:20
  • @Oleg this code resize the jqgrid width based on the content of each cell. The goal is resizing the width of each cell in jqgrid. – amanda chaw Nov 30 '14 at 00:23
  • I worked on one extension method of jqGrid which makes columns based on the width of content. See [the demo](http://www.ok-soft-gmbh.com/jqGrid/AutowidthColumn.htm). It uses `jQuery.jqGrid.autoWidthColumns.js` and `jQuery.jqGrid.setColWidth.js` which I published [here](https://github.com/OlegKi/jqGrid-plugins). I find the method slow, but it should be more quickly as youth I think. See [the answer](http://stackoverflow.com/a/26753600/315935) where I introduced `autoWidthColumns` method. – Oleg Nov 30 '14 at 00:27
  • I forget to mention that to use `autoWidthColumns` one need just call the method. Instead of `$grid.jqGrid({...})` one need to create it using `$grid.jqGrid("autoWidthColumns").jqGrid({...})`. So it's very simple to use it. – Oleg Nov 30 '14 at 00:34
  • @Oleg Thank you verymuch. I used $mygrid.jqGrid("autoWidthColumns").jqGrid({ }) but the grid just loaded one coloumn. – amanda chaw Nov 30 '14 at 00:38
  • @Oleg, this one give me the same issue. – amanda chaw Nov 30 '14 at 00:55
  • Optimize. You could go vanilla (raw JS), $ might just be awful. I agree with @Pointy, you are torturing the browser. – ProfNandaa Nov 30 '14 at 02:02
  • @ProfNandaa You mean I shouldn't use jquery? – amanda chaw Nov 30 '14 at 02:51
  • @amandachaw: Could you provide full demo which can be used to reproduce the problem? If `$mygrid.jqGrid("autoWidthColumns").jqGrid({ })` not worked then you probably included not all required JavaScript files: `jQuery.jqGrid.setColWidth.js` and `jQuery.jqGrid.autoWidthColumns.js`. Could you provide the demo which uses `autoWidthColumns` and which not works too? How many rows of data have your grid? How many columns? – Oleg Nov 30 '14 at 08:36
  • @Oleg, it works, but that issue that I mentioned in my question: "A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue." is still there. I have about 200 records and maybe it goes to 500 or 1000 records. – amanda chaw Nov 30 '14 at 10:12
  • @amandachaw: I asked you before to describe **what problem you try to solve**? Do you need to set the width of *one* column in the maximal width of the content of you have many columns? **Which formatters you use in the column/columns** and so on? It's better to provide the description of realistic problem as to try to solve *common problem* like `autoWidthColumns` do. I'm almost sure that one can provide permanent solution of the problem, but making common solution is more complex. – Oleg Nov 30 '14 at 13:08

1 Answers1

0

Try to keep in mind that JavaScript is entirely browser sided. Each browser will respond differently when it thinks your code times out. Furthermore, you can't bypass these errors. A great example would be chromes option to "stop this website from displaying anymore pop-ups." These features are added for the convenience of the end user and usually fix security holes or inform the user that the website is simply taking a while (which most users don't like)

One idea is to find a way to split up the amount of data you process. it seems like the issue, as you stated, is with large amounts of data. Is there a way to split the data up into "pages" and process, say, 50 items at a time?

If you can create stop points while it's updating that would work as well. The browser locks up while JavaScript runs which is a big part of the problem.

Finally, consider processing data on the server side and sending/receiving it with Ajax. This will let the browser/user work while your code is processed elsewhere and only stops to receive new data.

EDIT:

To address your comment:

Using math you could use nested for-loops to split the processing load into chunks of 50:

var numOfElements = /*how ever you count the records*/;
var elementsPerChunk = 50;
var numOfChunks = numOfElements / elementsPerChunk; //divide it into chunks

for (x = 0; x < numOfChunks; x++) {
    //Set Time out
    for (y = 0; y < elementsPerChunk; y++) {
        //Rest of code
    }
}

Note:

The above isn't perfect, for instance, you have to run the loop 1 more time to account for any sets of records that is not evenly divisible by 50 but you do not want to loop again if it is divisible by 50 (probably us mod operator to determine if there is a remainder and then add 1 if there is).

gNerb
  • 867
  • 2
  • 12
  • 28
  • Thank you for the answer. Is there anyway to split the above code to for example do that for every 50 record? and do that again? – amanda chaw Nov 29 '14 at 23:52
  • I tried to put setTimeout(function() { in the place that you told for setTimeout, but my code not running anymore. Am I something wrong with setTimeout? – amanda chaw Nov 30 '14 at 00:15
  • I tried to put setTimeout(function() { in the place that you told for setTimeout, but my code not running anymore. Am I something wrong with setTimeout? – amanda chaw Nov 30 '14 at 00:53