0

Is it possible to pause a for loop in javascript/jquery?

I have a $.each, that runs through a 63 long array, which have a for inside, which have another for, which have yet another for in it (Makes each>for>for>for), now each of the for loops through the array, this makes 63^4 (Equals 15752961) different combinations, and that takes time...

Sooo, is it possible to pause it 2sec, at 2k combinations?

Reason why I want to pause the loop, is to unlock the UI...

Code:

var $arr = ["","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9"],
len = $arr.length,
l = 0,
$("body").delay(1000).show(0, function(){
    $.each($arr, function(index, val){ // 63
        for(var i = 0; i < len; i++){ // 3969
            for(var j = 0; j < len; j++){ // 250047
                for(var k = 0; k < len; k++){ // 15752961
                    thing = val+i+j+k;
                    l++;
                    $("#loading").text(l+"/15752961");
                    console.log(l+"/15752961");
                    $("<div>"+thing+"</div><br />").prependTo("body");                                  
                }
            }
        }
    })
})

Ps. If someone think, they could clear up my question, please do so :D

/* EDIT */ If I try to run this server side, I get a server error, both if I use foreach or for

$smaa = range("a","z");
$store = range("A","Z");
$tal = range("0","9");
$arr = array_merge($smaa, $store, $tal);

for($i = 0; $i < $count; $i++){ // 62
    for($j = 0; $j < $count; $j++){ // 3844
        for($k = 0; $k < $count; $k++){ // 238328
            for($l = 0; $l < $count; $l++){ // 14776336
                $finish[] = $arr[$i].$arr[$j].$arr[$k].$arr[$l];
            }
            $finish[] = $arr[$i].$arr[$j].$arr[$k];
        }
        $finish[] = $arr[$i].$arr[$j];
    }
$finish[] = $arr[$i];
}

foreach($arr as $first){ // 62
    $finish[] = $first;
    foreach($arr as $second){ // 3844
        $finish[] = $first.$second;
        foreach($arr as $third){ // 238328
            $finish[] = $first.$second.$third;
            foreach($arr as $fourth){ // 14776336
                $finish[] = $first.$second.$third.$fourth;
            }
        }
    }
}

Please note, that I don't use both on the same time

Mobilpadde
  • 1,871
  • 3
  • 22
  • 29
  • And why do you need to pause it? What is the practical value for that? – VisioN May 31 '12 at 22:34
  • You can do ["chunk" looping / batch processing](http://stackoverflow.com/a/10344560/575527) to prevent the UI from freezing during the long loop. – Joseph May 31 '12 at 22:34
  • 4
    2 second pauses every 2k records would be ~4.5 hours x.x – Corbin May 31 '12 at 22:35
  • 1
    If you're iterating through the same 63 long array nested four levels deep, it does make me wonder what problem you're trying to solve! – Jeff Watkins May 31 '12 at 22:36
  • 1
    Do you mean you'd like the thread to yield every few seconds to unlock the UI? – Jeff Watkins May 31 '12 at 22:36
  • You need something like a queue and process it asynchronously. See [Asynchronous for cycle in JavaScript](http://stackoverflow.com/questions/4288759/asynchronous-for-cycle-in-javascript). – Felix Kling May 31 '12 at 22:36
  • Why are you scanning through the same array so many times? Convert the data to some other structure the first time through, such as a hash or tree, and only scan the data once. – starbolin May 31 '12 at 22:40
  • That seems excessive nesting: each > for > for > for. I don't think I've ever seen that, and I've been developing for 15 years. =( Perhaps if you post some code, that would help. – JMC May 31 '12 at 22:35
  • @JosephtheDreamer Yea, it's something like that, that I need :D – Mobilpadde May 31 '12 at 23:09
  • @JosephtheDreamer But, can't see how I'm gonna do it? I mean, I do a it in a `each`, and 3 `for`'s – Mobilpadde May 31 '12 at 23:23

3 Answers3

1

No, it's no possible to "pause" a for loop, and anyway it will not make it faster.

Don't use it here, but take a look at window.setTimeout(fn, delay)

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • But, I only have one function? – Mobilpadde May 31 '12 at 23:13
  • you absolutely can stop a loop, you return false to a wrapper function. – Fresheyeball May 31 '12 at 23:38
  • @Fresheyeball. He wants to pause not to stop. You can return anything you want to stop, but how would you continue? and let's you found a way (it can be done with a lot of spaghetti code) it will only cause the code to be slower. BTW: `return false` is a [jQuery thing](http://stackoverflow.com/a/10729215/601179). – gdoron May 31 '12 at 23:42
  • pausing inherently makes things slower, but I can understand why someone would want to. You can then restart it in a manner similar to the one in my answer, you rerun the loop but start the index at the where it left off last time. – Fresheyeball May 31 '12 at 23:44
  • @Fresheyeball. As you wish, my answer is still no, because this isn't solving anything. You just break the loop, increase the overhead, and start the loop again. I can't see any benefits here. – gdoron May 31 '12 at 23:46
  • Even if you don't see a benefit, doesn't make it impossible. Your answer is still inaccurate. – Fresheyeball May 31 '12 at 23:48
  • There are plenty of good reasons to pause a loop, even if this isn't one of them. – Fresheyeball May 31 '12 at 23:49
  • @Fresheyeball. I don't want to have a comments discussion, anyway, it does answer **this** question, if you don't like the answer, you can downvote it, this is why we have voting system here... – gdoron May 31 '12 at 23:51
1

No.

However, you can use something like this:

(function() {
    var i=0, j=0, k=0, timer;
    timer = setInterval(function() {
        // loop body here
        k++;
        if( k >= max_k) {
            k = 0;
            j++;
            if( j >= max_j) {
                j = 0;
                i++;
                if( i >= max_i) {
                    clearInterval(timer);
                }
            }
        }
    },1);
})();

I'm not sure how to integrate that with $.each, you may have to do it in plain JavaScript. But this code will basically run the loop as fast as possible while still redrawing.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Actually you might want to put one or two of the loops inside the `loop body here` part, otherwise this will take a minimum of 1,575.2961 seconds, or about half an hour. – Niet the Dark Absol May 31 '12 at 22:38
  • Even using setTimeout won't prevent the issue he/she is trying to avoid, namely the processing slowing down the UI. Web workers could be the proper solution but aren't supported in older versions of IE. But even using setTimeout won't stop the main thread from being dominated by generating that list for quite a few seconds. It just inserts in some points that something else *could* "interrupt" the calculations but in practice the UI still basically locks up. – pseudosavant Jun 01 '12 at 21:52
1

This is untested, but hopefully you will get the idea. Truthfully, this is something you probably should be handling on the server-side, or doing once and storing the output in the code.

var $arr = ["","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9"],
len = $arr.length,
l = 0,
paused = false,
writer = '',
pauseAt = 2000;

$("body").delay(1000).show(0, function(){

    function killForTwoSeconds(){ //function to timeout loop
         paused = true; //set to true to kill loop
         $('body').append(writer); //write to body only on pause (fewer writes to dom = faster script)
         setTimeout(function(){ // wait for 2 seconds
              paused = false;
              loopIt(); // re-run loop
         },2000);
    }

    function loopIt(){
        $.each($arr, function(index, val){ 
            for(var i = l; i < len; i++){ 
                for(var j = l; j < len; j++){ //loops now start at l instead of 0 so when loop restarts it restarts at the right place
                    for(var k = l; k < len; k++){ 
                        if(l % pauseAt === 0){ // if l is divisible by 2000 kill 
                            killForTwoSeconds();
                        }
                        if(!paused){ //if not paused add item to writer
                            thing = val+i+j+k;
                            l++;
                            $("#loading").text(l+"/15752961");
                            console.log(l+"/15752961");
                            writer = "<div>"+thing+"</div><br />";                                  
                        }else if(index === len-1 && k === len-1){
                            $('body').append(writer); //final write
                        }else{
                            return false; // if paused return false
                        }
                    }
                }
            }
        });
    }
});
Fresheyeball
  • 29,567
  • 20
  • 102
  • 164