Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting JavaScript Timeout limit in Google Chrome

Is it possible to increase the time out limit for JavaScript?

If I have a script that executes for more than 20/30 seconds chrome will pop-up with the unresponsable page dialog.

Making a more efficient script won't help me because the script sometimes need to iterate through a function for a million or billion times

like image 300
Tyilo Avatar asked Feb 03 '23 17:02

Tyilo


2 Answers

To split the function on steps/chunks and run those inside setInterval(function(){}). This way page will be responsive, you will be able to notify user about progress of execution and you will get your job done.

UPDATE: Here is simple function that takes worker function executing each iteration, chunksz - number of iteration running in single chunk maxit - total number of iterations.

function task(worker, chunksz, maxit)
{
  var idx = 0;
  var xint = null;
  function exec_chunk() 
  {
     for(var n = 0; n < chunksz; ++n)
     {
       if(idx >= maxit) { return; }
       worker(idx++);
     }
     setTimeout(exec_chunk,1);
  }
  exec_chunk();
}

Here is an example : http://jsfiddle.net/Ed9wL/ As you see you get all iterations in order.

UPDATE2:

Say you have a loop:

 for(var i=0; i<100000; ++i) { ... do something ... }

then you need to wrap body of the loop into a function and call the task above with it like this:

task(function(i){ ... do something ... },100, 100000);

or like this:

function loopBody(i){ ... do something ... }
task(loopBody,100, 100000);
like image 120
c-smile Avatar answered Feb 05 '23 16:02

c-smile


When you have lots of processing to do client side, you need to split out your work into separate threads. The browser only has a single thread for handling user input (events) and for processing JS. If you're processing too much JS, without yielding, the UI becomes unresponsive and the browser is not happy.

How can you allow your script to yield? The new way is to use web workers http://www.whatwg.org/specs/web-workers/current-work/ . This works by creating a separate thread to run your JS, thread thread does not access to the DOM and can be run concurrently.

However, this newer technology doesn't exist in all browsers. For older browsers, you can split up your work by having the script call itself through timeouts. Whenever a timeout occurs, the script is yielding to the browser to run its events, once the browser is done, your next timeout will be triggered.

Example http://jsfiddle.net/mendesjuan/PucXf/

var list = [];
for (var i = 0; i < 500000; i++) {
   list.push(Math.random());
}


function sumOfSquares(list) {  
  var total = 0;
  for (var i = 0; i < list.length; i++) {
      total += list[i] * list[i];
      // DOM manipulation to make it take longer
      var node = document.createElement("div");
      node.innerHTML = "Sync temp value = " + total;
      document.body.appendChild(node);
  }
    return total;
}


function sumOfSquaresAsync(arr, callback) {
  var chunkSize = 1000; // Do 1000 at a time
  var arrLen = arr.length;
  var index = 0;
  var total = 0;  

  nextStep();

  function nextStep() {
     var step = 0;
     while (step < chunkSize && index < arrLen) {
       total += arr[index] * arr[index];
       // DOM manipulation to make it take longer
       var node = document.createElement("div");
       node.innerHTML = "Async temp value = " + total;
       document.body.appendChild(node);         
       index++;
       step++;
     }

     if (index < arrLen) {
        setTimeout(nextStep, 10);
     } else {
       callback(total);
     }
  }
}



sumOfSquaresAsync(list, function(total) {console.log("Async Result: " + total)});

//console.log("Sync result" + sumOfSquares(list));

The example on jsfiddle has the synchronous call commented out, you can put it back in to see the browser come to a crawl. Notice that the asynchronous call does take a long time to complete, but it doesn't cause the long running script message and it lets you interact with the page while calculating (select text, button hover effects). You can see it printing partial results on the pane to the bottom right.

UPDATE http://jsfiddle.net/mendesjuan/PucXf/8/

Let's try to use c-smile's task function to implement sum of squares. I think he's missing a parameter, a function to call back when the task is finished. Using task allows us to create multiple chunked functions without duplicating the work of calling setTimeout and iteration.

/**
 * @param {function} worker. It is passed two values, the current array index, 
 *        and the item at that index
 * @param {array} list Items to be traversed
 * @param {callback} The function to call when iteration is finished;
 * @param {number} maxit The number of iterations of the loop to run 
 *        before yielding, defaults to 1000
 */
function task(worker, list, callback, maxit)
{
  maxit = maxit || 1000; 
  var idx = 0;
  exec_chunk();
  function exec_chunk() 
  {
     for(var n = 0; n < maxit; ++n)
     {
       if(idx >= list.length) {
         callback(); 
         return;
       }
       worker(idx, list[idx]);
       idx++;
     }
     setTimeout(exec_chunk,1);
  }
}


function sumOfSquaresAsync(list, callback) 
{
   var total = 0;

   // The function that does the adding and squaring
   function squareAndAdd(index, item) {
      total += item * item;
      // DOM manipulation to make it take longer and to see progress
      var node = document.createElement("div");
      node.innerHTML = "Async temp value = " + total;
      document.body.appendChild(node);                
   }

   // Let the caller know what the result is when iteration is finished
   function onFinish() {
      callback(total);
   }

   task(squareAndAdd, list, onFinish);

}

var list = [];
for (var i = 0; i < 100000; i++) {
   list.push(Math.random());
}

sumOfSquaresAsync(list, function(total) {
    console.log("Sum of Squares is " + total);        
})
like image 36
Juan Mendes Avatar answered Feb 05 '23 18:02

Juan Mendes