Is there a command or function in Javascript that controls the screen update before the loop ends?

Asked

Viewed 757 times

3

Just one example:

<script>
for (var i=0;i<10;i++) { //Inicia loop for para contar de 0 até 9
 var t=0; // inicia variável t com valor 0
 while(t<1000000) { //inicia loop enquanto t for menor que 1000000
   t++; //Incrementa o t, ou seja, t = t + 1
 } // Encerra o loop while, que neste caso não faz nada apenas cria um delay, mantendo o processador ocupado com a contagem, propositadamente!
 document.getElementById('mensagem').innerHTML = `teste msg na tela ${i}` // Envia uma mensagem para a tela através de uma DIV por exemplo <<<aqui não funciona em tempo real>>>
 console.log(`teste msg na tela ${i}`)//Envia mensagem para o console <<<aqui está funcionano em tempo real>>>
} // finaliza o loop for, se for menor que 10 volta para a linha "var t=0"
</script>

What I expected was to send a message on the screen at each "delay", but this does not happen, it only displays the 10 messages on the screen when the loop ends. Does anyone there know any commands to force the display of the text at the exact moment it is sent, within the loop? I intend to use this to update the Progress bar of a JS function that handles files and often takes time to finish, the user thinks that the browser has locked and closes the window before the function ends. If anyone can help, I’d be grateful! Obs. I tried with setTimeout, some artificials to force the Rendering, anyway, for now nothing worked, remembering that the above code is just a simple example to illustrate my problem.

  • What are you looking for, something like a Promise? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

  • Ever tried to use setInterval?

  • I tried, but it didn’t work either. I don’t have much experience with JS, but it seems to me to be a conceptual problem of language, while running a function does nothing else until it finishes that function. In my head a time interruption (setInterval or setTimeOut) should have priority in the execution, but in practice it seems that it does not happen...

  • After you fire the setInterval, it keeps running regardless of whether other things are being executed in the script. From what I could understand, it would be enough to fire a setInterval showing something on the screen, and when your preview is finished, just cancel the setInterval.

  • If I change "Document.get..." by "console.log" I can monitor the way I want in real time by the console monitor, then it works perfectly. But I need to do it through the browser screen.

  • I’ve done this test with setInterval, when it enters the loop, stops updating the screen and only returns when the loop ends.

  • Ever tried to put += in place of = after the document.get...?

  • 2

    The fact is that under normal conditions you should not make the code this way in JS (nor in any language practically). Even if there was what you want, still a code that consumes all processing can be considered as having a bug if that is not a specific goal of it. Even codes that run 24/7 usually have a point where they release the CPU, except in case of intense calculations and things like that (such as a machine dedicated to finding prime numbers or mining of alguisacoins)

Show 3 more comments

3 answers

2


Javascript is a single thread language which means that the HTML display will only be updated after the loop is finished.

To make your HTML be updated in a loop you would need to use a hypothetical asynchronous repeat loop.

The language does not offer this loop of asynchronous repetition but it is possible to obtain this functionality through the method setInterval() which creates a timer by repeating the call of a function in a time interval defined in milliseconds and which returns an identifier for the timer.

To stop this timer use the function clearInterval() which accepts as parameter the identifier for the timer you want to interrupt.

var i = 0;
var j = 0;

var menssagem = document.getElementById('mensagem');
//Executa o laço a cada décimo de segundo
var loop = setInterval(() => {
  menssagem.innerText = `teste msg na tela ${i}`;
  if (i >= 10) {
    clearInterval(loop); //Se i for maior ou igual a dez encerra o laço
  } else {
    i++; //Se i for menor que 10 incrementa i 
  }
}, 100);
//Executa um segundo laço em paralelo em com duração
//e um tempo de atualização diferentes
var loop2 = setInterval(() => {
  console.log(`teste msg no console ${j}`);
  if (j >= 20) {
    clearInterval(loop2);
  } else {
    j++;
  }
}, 55);
<span>Teste em tempo real: <span id='mensagem'></span></span>

  • 1

    Just an addendum, you can also use the setInterval on a break 0 'cause he’s already in line callback because it is asynchronous, no matter the "waiting time". Related: https://answall.com/a/184783/100416

1

Here is an example of loading using setInterval. The setInterval expects as the first parameter a function that will be executed asynchronously at each time interval.

let perc = 0;
let id = null;
$(document).ready(() => {
	id = setInterval(() => {
  	console.log("executing function");
  	perc += 10;
  	$('.progress-bar').css('width', perc+'%').attr('aria-valuenow', perc);
    $('.progress-bar').innerHtml = perc + "%";
    if(perc >= 100) {
    	clearInterval(id);
    }
  }, 1000);
});
.row {
  background: #f8f9fa;
  margin-top: 20px;
}

.col {
  border: solid 1px #6c757d;
  padding: 10px;
}
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.slim.js"></script>
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.js"></script>
<script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.js"></script>
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css">

<div class="progress">
  <div class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>

Follows jsFiddle: https://jsfiddle.net/cf9w7eur/9/

  • I appreciate the attempt to help me, but I still have the same problem: The presented bar works perfectly, updating every second, until then ok, but just call a second function that takes more than a few seconds to run and the bar is stopped, It will only be updated when this second function, which would be precisely the objective, will be to monitor the progress of this second function, monitoring in real time. I don’t understand why setInterval has no priority over a function or loop for example.

  • javascript is single thread and works like a 1 core CPU. It divides processing time. If you bombard the thread with a loop without delay. The function will not run. If it results send the way you are doing the processing. I can help you better, I guarantee you have better solution than that while immense.

  • This immense while was just a way that I found to illustrate in a simple way my real problem, in practice it is a function that handles 32-bit files and has "for" loops for this manipulation. My goal, as long as this manipulation occurs, was to have a real-time, graphic, or simple "processing x de y" type of text on the screen, where x would be current and y the total. But all attempts were frustrated because the screen only receives the msg when it finishes the function, so I’m realizing there is no solution with Javascript, would have to go to the back end in another language...

1

Your loop only displays the message after the end of your loop, because that is exactly what is written in the code, see:

for (var i=0;i<10;i++) {
 var t=0;
 while(t<1000000) {
   t++;
 }
 document.getElementById('mensagem').innerHTML = `teste msg na tela ${i}` //a mensagem so esta sendo exibida logo apos todo o seu loop for concluido
}

if you want it to appear before the loop of the command (for) try placing your message inside the while block:

for (var i=0;i<10;i++) {
 var t=0;
 while(t<1000000) {
   document.getElementById('mensagem').innerHTML = `teste msg na tela ${i}`
   t++;
 }
}

however in this code snippet your message will appear until the variable T reaches the value 1000000, after that the (for) will repeat for 10 times without doing anything because your variable T will already be worth 1000000, if you want to appear 1000000 for once and stop the command (for) recommend writing this way:

for (var i=1;i<1;i--) {
 var t=0;
 while(t<1000000) {
   document.getElementById('mensagem').innerHTML = `teste msg na tela ${i}`
   t++;
 }
}

this way the command (for) will not repeat 10 times, what will repeat is the while for 1000000 times and each time it repeats will show your message.

Alternatively, repeat the command (for) 10 times showing the message per 1000000 times per 10 times:

for (var i=0;i=10;i++) {
     var t=0;
     while(t<1000000) {
       document.getElementById('mensagem').innerHTML = `teste msg na tela ${i}`
       t++;
     }
       var t = 0;
    }

hope I’ve helped!

  • Thank you Muriel, but in the first example I put if you look closely the text is being sent inside the "for" loop, and not outside. If you put it inside the while loop (in this example only to create a delay), the message would be sent 1000000 times instead of 10. This is just an example, the point is that the message does not go to the screen in real time as it occurs in "console.log". And so, my question remains, is that there is some command that forces the browser to display the message and then continue the loop, even if this implies greater slowness. I hope I explained it clearly.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.