RobertIT
RobertIT

Reputation: 121

HTML page doesn't update while a javascript function running

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>

Upvotes: 3

Views: 2305

Answers (4)

RobertIT
RobertIT

Reputation: 121

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>

Upvotes: 0

Jan-Luca Klees
Jan-Luca Klees

Reputation: 536

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>

Upvotes: 4

georgeawg
georgeawg

Reputation: 48968

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.

Upvotes: 1

Tigger
Tigger

Reputation: 9130

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>

Upvotes: 0

Related Questions