views:

93

answers:

3

I am using jQuery to load a massive table in batches of rows. I am loading the initial rows, then I make $.ajax calls to append rows to the body of the table. On completion of the insertion of the next chunk of rows, I call the method to process the next chunk of rows. See code below. The problem is, even after all the content is loaded, the javascript still claims to be executing - when I go to navigate to another page is complains that there is a javascript routine slowing down the page and do I want to abort it. At this point, it shouldn't be running! This routine is initially called from the $(function() {...}) routine (on ready). Any ideas how I am supposed to stop this from continuing after it has completed all it's work?

        function processNextChunk(c, t, s, p, x) {
        var args = "{company_ID:" + c + ",shareholdingType:" + t + ",startIndex:" + s + ",pageSize:" + p + ",stack:'" + x + "'}";
        //alert(args);
        $.ajax({
            type: "POST",
            url: "TestStructure6.aspx/GetNextHierarchyPage",
            data: args,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function(msg) {
                //Append the content to the bottom of the table tag.
                //Returning 2 arguments from the result, hence the split (initial
                //value is an int, so not a big deal using pipe as a delimiter)
                if (msg.d.length > 0) {
                    var slash = msg.d.indexOf('|');
                    var r;
                    if (slash > 0) {
                        x = msg.d.substr(0, slash);
                        r = msg.d.substr(slash + 1, msg.d.length - slash);
                        $('#h  > tbody').append(r);
                        if (r.length > 0) {
                            var percent = (s + p) / totalRows * 100;
                            $('#counter').html(parseInt(percent) + '%');
                            setTimeout('processNextChunk(' + c + ', ' + t + ', ' + (s + p) + ', ' + p + ', "' + x + '")', 0);
                            //processNextChunk(c, t, s + p, p, x)
                        }
                        else {
                            $('#counter').html('');
                        }
                    }
                }
                return true;
            }
        });
        return true;
    }
+2  A: 

This may or may not solve your problem, but you shouldn't be calling setTimeout with a string argument.

Instead, you should give it a function, like this:

setTimeout(function() {
    processNextChunk(c, t, s + p, p);
}, 0);

Also, instead of writing $('#counter').html(''), you can write $('#counter').empty().

To solve your problem, are you sure that your setTimeout call in recursing forever?

SLaks
thanks for the advice, I have now added the empty statement. Even when I have removed the timer, I experience the same problem. Introducing the timer was my attempt to prevent recursion, which I thought might be occuring because the processNextChunk is calling itself.
Tone
Adding the timer wouldn't help - it's still calling itself. Use a debugger to step through your code and check whether it's recuring forever.
SLaks
The debugger shows the word "blank" next to a notepad icon under the VS2008 debugger for every execution of the $.ajax call. It shows one for every chunk of rows requested, and it stops adding them when there are no more rows. That implies that this is not a case of having a never-ending routine, but that I'm somehow not cleanly exiting my request perhaps?
Tone
A: 

I can't quite tell what data is returned in the event you have retrieved all rows. I am assuming it is supposed to fail the check:

r = msg.d.substr(slash + 1, msg.d.length - slash);

If this is the case, you may be able to use clearTimeout() in your else clause just after:

$('#counter').html('');
cballou
you are correct, the "r" variable is what contains my chunk of rows. Having to cancel all timers would be a pain as I would then need to track all the timer IDs, right?
Tone
+1  A: 

You are calling setTimeout(...,0) aka a zero timeout. In other words, you are not allowing the browser to update/redraw.

Note that this is browser dependent - some testing on various machines over the years indicates that winxp requires at least a timeout of 50, while linux requires a timeout of 10. It appears this is related to the minimum timeslice of the OS schedular.

If you are on a fast connection (eg: localhost development), maybe the ajax call is responding fast enough so that setting it to zero is a problem...

Your code looks like it could do with simply increasing the timeout to something larger, say 1 second, without ill effects.

[ Calling setTimeout with a string argument is perfectly valid, but it looks like you aren't quoting correctly. ]

Mathew
Browsers move the timeout value up to the least they can handle. The timeout will execute when the current thread is complete and all browsers will refresh in between. String values to timeout are equivalent to eval() and if not invalid, simply bad practice.
Borgar
I tried this, and also changed to using a function call instead of eval version, and it made no difference.
Tone