3

Chrome, FF. Opera and probably others browser show only the 100000 number at end of process, but i want see displayed in sequence 1..2..3..4...100000. This code doesn't work well:

<html>
<head>
</head>
<body>

<button type="button" onclick="showSequence();">Show the numbers one at a time!</button>
<p id="herethenumbers">00</p>

<script>
function showSequence() {                   
    el = document.getElementById('herethenumbers'); 
    for(var nn=0;nn<=100000;nn++){  
        el.innerHTML = nn;      
    }
}
</script>
</body>
</html>

window.setTimeout isn't possible using when you don't know the execution time of a given process and even changing the attributes of the main div object (visibility e.g.) does not work for me.

Thanks at all.


UPDATE

Here a partial solution.

Allows you to view the status of a long process, for now, unfortunately only the beginning and the end of the (single) process.

<html>
<head>
</head>
<body>

<button type="button" onclick="executeMultiLongProcess();">Launch and monitoring long processes!</button>
<p id="statusOfProcess"></p>

<script>
var el = document.getElementById('statusOfProcess'); 

function executeMultiLongProcess() {                   
    processPart1();
}
function processPart1() {
    el.innerHTML = "Start Part 1"; 
    setTimeout(function(){ 
        for(var nn=0;nn<=100000000;nn++){  //.. 
        }
        el.innerHTML = "End Part 1";        
        window.setTimeout(processPart2, 0);     
    },10);
}
function processPart2() {
    el.innerHTML = "Start Part 2"; 
    setTimeout(function(){ 
        for(var nn=0;nn<=100000000;nn++){  //.. 
        }
        el.innerHTML = "End Part 2";
        window.setTimeout(processPartN, 0);
    },10);
}
function processPartN() {
    el.innerHTML = "Start Part N"; 
    setTimeout(function(){ 
        for(var nn=0;nn<=100000000;nn++){  //.. 
        }
        el.innerHTML = "End Part N"; 
    },10);
}
</script>
</body>
</html>
georgeawg
  • 48,608
  • 13
  • 72
  • 95
RobertIT
  • 113
  • 8
  • 4
    That's just how things work. There's no reason for the browser to update the view while the code is running, so it doesn't. – Pointy Mar 10 '19 at 18:46
  • A simple reason is update the user about the status of the process – RobertIT Mar 10 '19 at 18:57
  • 1
    @Pointy was trying to point out that when the browser executes the code it has rules for when it will update the screen. If you want the browser to behave in a particular way you need to understand those rules and how to manipulate them. There is no place in that for loop where the browser is either given the chance to redraw the screen, or where it is told to redraw the screen. – Jason Aller Mar 10 '19 at 19:47
  • @Jason Alle, I tried to do it, using for example: el.style.visibility = "hidden"; el.innerHTML = nn; el.style.visibility = "visible"; but the browser seems to ignore any kind of change of state – RobertIT Mar 10 '19 at 19:58
  • Maybe I'm missing something, but why won't 'el.innerHTML = el.innerHTML + nn + '
    ';' work? That should show the count in sequence. Change the '
    ' to ', ' if you want all numbers on 1 line.
    – CharlesEF Mar 10 '19 at 23:24
  • @CharlesEF - my goal is show the advancement in a javascript function which can take a few minutes, for example show a counter or a progress bar, the browser until gets the focus again doesn't show any variation of the elements on the screen – RobertIT Mar 11 '19 at 00:03

4 Answers4

4

I want to suggest using window.requestAnimationFrame rather than setTimeout or setInterval as it allows you to wait for the browser to render changes and right after that, execute some code. So basically you can do:

window.requestAnimationFrame( () => {
  el.innerHTML = nn;
} );

I changed your function to be recursive. This way I can call the function to render the next number inside the window.requestAnimationFrame callback. This is necessary, as we ought to wait for the browser to render the current number and just after that, instruct the browser to render the next one. Using window.requestAnimationFrame inside the for loop would not work.

el = document.getElementById( 'herethenumbers' );

function showSequence( nn=0 ) {                   
  if( nn <= 100000 ) {
    window.requestAnimationFrame( () => {
      el.innerHTML = nn;
      showSequence( nn + 1 );
    } );
  }
}
<button type="button" onclick="showSequence();">
    Show the numbers one at a time!
</button>

<p id="herethenumbers">00</p>
Jan-Luca Klees
  • 516
  • 4
  • 8
1

Use window.setInterval:

function showSequence() {                   
    var el = document.getElementById('herethenumbers');
    var nn = 0;
    var timerId = setInterval(countTo100, 80); 
    function countTo100(){  
        el.innerHTML = nn;
        nn++;
        if (nn>100) clearTimeout(timerId);      
    }
}
<button type="button" onclick="showSequence();">
   Show the numbers one at a time!
</button>
<p id="herethenumbers">00</p>

Update

the scenario is a bit different. You have a javascriot process that starts and ends without interruptions, it can work several minutes in the meantime, inside it, must show on screen the status of its progress.

JavaScript is single-threaded in all modern browser implementations1. Virtually all existing (at least all non-trivial) javascript code would break if a browser's javascript engine were to run it asynchronously.

Consider using Web Workers, an explicit, standardized API for multi-threading javascript code.

Web Workers is a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can perform I/O using XMLHttpRequest (although the responseXML and channel attributes are always null). Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa).

For more information, see MDN Web API Reference - Web Workers.

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Thanks georgeawg, this works but the scenario is a bit different. You have a javascriot process that starts and ends without interruptions, it can work several minutes in the meantime, inside it, must show on screen the status of its progress. – RobertIT Mar 10 '19 at 22:50
  • WebWorkers is very interesting, but like the documentation says "you can not directly manipulate the DOM from inside to worker, or use some default methods and properties of the window". This excellent solution can only be used in specific cases – RobertIT Mar 11 '19 at 00:58
0

Sample code below using setTimeout, only counts up to 100 for the sample.

Might want to check out Difference between setTimeout with and without quotes and parentheses

And then there is also: 'setInterval' vs 'setTimeout'

var delayId = null, frameTime = 25, countTo = 100, el, nn = 0;
function increment(e) {
  if (delayId) {
    window.clearTimeout(delayId);
  }
  el.textContent = nn++;
  if (nn <= countTo) {
    delayId = window.setTimeout(increment,frameTime);
  }
}
window.onload = function() {
    el = document.getElementById('herethenumbers');
    var b = document.getElementById('start');
    b.addEventListener("click",increment,false);
}
<button type="button" id="start">Show the numbers one at a time!</button>
<p id="herethenumbers">00</p>
Tigger
  • 8,980
  • 5
  • 36
  • 40
0

Using requestAnimationFrame as suggested by Jan-Luca Klees is the solution to my problem, here a simple example of use of requestAnimationFrame. Allows you to run one or more long-duration processes with the interaction with objects on screen (a popup for example or others), requestAnimationFrame tells the browser you want to run an animation and you want the browser to call a specific function to update a animation.

<html>
<head>
</head>
<body>

<button type="button" onclick="startProcesses();">Start long duration process!</button>
<p id="status">Waiting to start processes</p>

<script>
el = document.getElementById('status');

var current_process = 1;
var total_process = 2; 
var startEnd = 'S';

function startProcesses() {                   

    function step(timestamp) {
        if(current_process==1 && startEnd=='E') res = process1();
        if(current_process==2 && startEnd=='E') res = process2();       
        //..n processes

        if(startEnd=='S') el.innerHTML = "Process #"+current_process+" started..";
        if(startEnd=='E') el.innerHTML = "Process #"+current_process+" "+res;

        if(startEnd=='S' || current_process<total_process) {
            if(startEnd=='E') current_process++;
            startEnd = (startEnd=='S'?'E':'S'); 
            window.requestAnimationFrame(step);     
        }else{
            el.innerHTML = "Process #"+current_process+" "+res;
        }
    }
    window.requestAnimationFrame(step);
}

function process1() {                
    for(var nn=0;nn<=10000;nn++){  
        console.log(nn);
    }
    return "Success!"; //or Fail! if something went wrong
}
function process2() {                                
    for(var nn=0;nn<=10000;nn++){  
        console.log(nn);
    }
    return "Success!"; //or Fail! if something went wrong
}
</script>
</body>
</html>
RobertIT
  • 113
  • 8