2

I'm running a long loop and need to report the loop's progress.

var mLog=document.getElementById("log");
for (n = 2; (n<10000 && calc_power<power); n=n*2)
{
  calc_power=chi_power(n,w,df,delta1,alfa);
  var message="n="+n+"<br>";
  window.setTimeout(progress(mLog,message), 0);
}

function progress (mLog,message)
{  
  mLog.innerHTML+=message;
}

I used the window.setTimeout as recommended but still, the HTML page update is being done only after the loop is ended...

  • Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Obsidian Age Mar 27 '18 at 00:59
  • You may be using `setTimeout`, but that's not "as recommended". As written, your entire computation has to finish before anything else gets time to run, and what you end up with is a very big queue of of tiny innerHTML updates waiting to run after the computation finishes. – kshetline Mar 27 '18 at 01:09

3 Answers3

2

The loop is synchronous, so it will run until it ends before any function in a setTimeout() is executed.

You would have to turn your loop into a function and so that it would call itself back using setTimeout:

var mLog = document.getElementById("log");

var w, df, delta1, alfa;            // fake implementation, for demo only
function chi_power(n) { return n; } // fake implementation, for demo only

var calc_power = 0, power = 5000;   // fake data, for demo only

function calculate(n) {
  if (n<10000 && calc_power<power) {
    calc_power=chi_power(n,w,df,delta1,alfa);
    var message="n="+n+"<br>";
    progress(mLog,message);

    // proceed with the loop
    setTimeout(function () { calculate(n*2); }, 0);
  }
}

function progress(mLog, message) {
  mLog.innerHTML += message;
}

calculate(2);
<div id="log"></div>
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
  • It worked. the only problem was that any other activities after calculate(2); started immediately after first iteration was ended. so I moved it to be "else" in function calculate(n) – Oren Ben-Harim Mar 27 '18 at 07:20
  • Sure thing! Makes sense! Btw, I see you are a new user, JSYK, if the question/answer works, you can mark it so we know it is: https://meta.stackexchange.com/a/5235/219205 – acdcjunior Mar 27 '18 at 11:21
0

Your loop is synchronous, but the setTimeout function will only trigger after the loop ends, because the block calling the loop is still on the stack. setTimeout could work if you want to report the progress of multiple things that are asynchronous*, but don't use it for something synchronous.

You'll have to periodically check if the condition is met for displaying progress, eg, in the for loop:

if (n % 500 === 0) progress(mLog, message);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • I started with this method, actually update every n, but the problem was that it updated the HTML only after finishing the loop. thanks anyway – Oren Ben-Harim Mar 27 '18 at 07:10
0

Please check the asynchronous way with recursion:

var mLog=document.getElementById("log");
var n = 2;
function progress (mLog,message)
{  
  mLog.innerHTML+=message;
}
function asyncLoop(n) {
  if(n >=10000) return;
  //calc_power=chi_power(n,w,df,delta1,alfa);
  var message="n="+n+"<br>";
  progress(mLog,message);
  window.setTimeout(asyncLoop(n*2), 0);

}
asyncLoop(n);
<div id = "log"> </div>
I. Ahmed
  • 2,438
  • 1
  • 12
  • 29
  • `window.setTimeout(n*2, 0);` won't work. `n*2` is not a function. – kshetline Mar 27 '18 at 01:14
  • Sorry, still won't work. The first item in `setTimeout` has to be a function by itself, not a function call passing an argument. `asyncLoop(n*2)` will be called immediately and evaluated, then passed as an invalid argument to setTimeout. – kshetline Mar 27 '18 at 01:16
  • Please check the fiddle – I. Ahmed Mar 27 '18 at 01:20