Home > DeveloperSection > Forums > How to break up a long running function in javascript, but keep performance
Pravesh Singh

Total Post:411

Points:2881
Posted on    May-03-2013 1:20 AM

 JavaScript JavaScript 
Ratings:


 1 Reply(s)
 1002  View(s)
Rate this:
Hi Expert!

I have a long running function. Which iterates through a large array and performs a function within each loop.

longFunction : function(){
       var self = this;
       var data = self.data;

       for(var i=0; len = data.length; i<len; i++){
              self.smallFunction(i);
       }
},
smallFunction : function(index){

// Do Stuff!

}
For the most part this is fine but when I am dealing with arrays above around 1500 or so we get to the point of recieving a javascript execution alert message.

So I need to break this up. My first attempt is like so:

longFunction : function(index){
       var self = this;
       var data = self.data;


      self.smallFunction(index);

      if(data.slides[index+1){
         setTimeout(function(){
            self.longFunction(index+1);
         },0);
      }
      else {
               //WORK FINISHED
      }

},
smallFunction : function(index){

// Do Stuff!

}
So here I am removing the loop and introducing a self calling function which increases its index each iteration. To return control to the main UI thread in order to 

prevent the javascript execution warning method I have added a setTimeout to allow it time to update after each iteration. The problem is that with this method 

getting the actual work done takes quite literally 10 times longer. What appears to be happening is although the setTimeout is set to 0, it is actually waiting more 

like 10ms. which on large arrays builds up very quickly. Removing the setTimeout and letting longFunction call itself gives performance comparable to the original 

loop method.

I need another solution, one which has comparable performance to the loop but which does not cause a javascript execution warning. Unfortunately webWorkers cannot be 

used in this instance.

It is important to note that I do not need a fully responsive UI during this process. Just enough to update a progress bar every few seconds.

Would breaking it up into chunks of loops be an option? I.e. perform 500 iterations at a time, stop, timeout, update progress bar, perform next 500 etc.. etc..

Is there anything better?

ANSWER:

The only solution seems to be chunking the work.

By adding the following to my self calling function I am allowing the UI to update every 250 iterations:

 longFunction : function(index){
           var self = this;
           var data = self.data;


          self.smallFunction(index);

          var nextindex = i+1;

          if(data.slides[nextindex){
            if(nextindex % 250 === 0){
             setTimeout(function(){               
                self.longFunction(nextindex);
             },0);
            }
            else {
                self.longFunction(nextindex);
            }
          }
          else {
                   //WORK FINISHED
          }

    },
    smallFunction : function(index){

    // Do Stuff!

    }
All I am doing here is checking if the next index is divisible by 250, if it is then we use a timeout to allow the main UI thread to update. If not we call it again directly.

Please help me!


AVADHESH PATEL

Total Post:604

Points:4228
Posted on    May-03-2013 9:07 AM

Hi Pravesh!

Here's some batching code modified from an earlier answer I had written:

var n = 0,
    max = data.length;
    batch = 100;

(function nextBatch() {
    for (var i = 0; i < batch && n < max; ++i, ++n) {
        myFunc(n);
    }
    if (n < max) {
        setTimeout(nextBatch, 0);
    }
})();

I hope it resolve your problem!

Don't want to miss updates? Please click the below button!

Follow MindStick