JavaScript. a loop with innerHTML is not updating during loop execution - javascript

I'm trying to refresh a div from Javascript at each loop and see 1, 2, 3, ....
The following code works, but only displays the final result (9998).
How is it possible to display all the steps?
Thank you in advance.
<html>
<head>
</head>
<body>
<div id="cadre" style="width=100%;height=100%;">
<input type="button" value="Executer" onclick="launch();"/>
<div id="result" ></div>
</div>
<script type="text/javascript">
function launch(){
for (inc=0;inc<9999;inc++){
document.getElementById('result').innerHTML = inc;
}
}
</script>
</body>
</html>

JavaScript execution and page rendering are done in the same execution thread, which means that while your code is executing the browser will not be redrawing the page. (Though even if it was redrawing the page with each iteration of the for loop it would all be so fast that you wouldn't really have time to see the individual numbers.)
What you want to do instead is use the setTimeout() or setInterval() functions (both methods of the window object). The first allows you to specify a function that will be executed once after a set number of milliseconds; the second allows you to specify a function that will be executed repeatedly at the interval specified. Using these, there will be "spaces" in between your code execution in which the browser will get a chance to redraw the page.
So, try this:
function launch() {
var inc = 0,
max = 9999;
delay = 100; // 100 milliseconds
function timeoutLoop() {
document.getElementById('result').innerHTML = inc;
if (++inc < max)
setTimeout(timeoutLoop, delay);
}
setTimeout(timeoutLoop, delay);
}
Notice that the function timeoutLoop() kind of calls itself via setTimeout() - this is a very common technique.
Both setTimeout() and setInterval() return an ID that is essentially a reference to the timer that has been set which you can use with clearTimeout() and clearInterval() to cancel any queued execution that hasn't happened yet, so another way to implement your function is as follows:
function launch() {
var inc = 0,
max = 9999;
delay = 100; // 100 milliseconds
var iID = setInterval(function() {
document.getElementById('result').innerHTML = inc;
if (++inc >= max)
clearInterval(iID);
},
delay);
}
Obviously you can vary the delay as required. And note that in both cases the inc variable needs to be defined outside the function being executed by the timer, but thanks to the magic of closures we can define that within launch(): we don't need global variables.

var i = 0;
function launch(){
var timer = window.setInterval(function(){
if( i == 9999 ){
window.clearInterval( timer );
}
document.getElementById('result').innerHTML = i++;
}, 100);
}
launch();

Try
document.getElementById('result').innerHTML += inc;

Related

Counter not displaying each number, just shows final total

Why is it that the counter only shows final number vs seeing each number 1 by 1.
What needs to be done to accomplish this?
var counter = 100;
function countdown() {
while(counter < 1000) {
counter++;
console.log(counter);
document.getElementById('cc').innerHTML = counter;
}
}
countdown();
setInterval(countdown, 1000);
This problem is happening because the Javascript execution and page rendering are actually occurring in the same execution thread. This means that while the code is executing the browser will not be redrawing the page because running JavaScript blocks the updating of the DOM like in your example.
To solve this you can use the setTimeout() which allows you to specify a function that will be executed once after a set number of milliseconds. Now, there will be gaps in between the code execution in which the browser will get the chance to redraw the page. now, when you actually pass 0 as the the delay argument. it will schedule the callback to be run asynchronously, after the shortest possible delay - which will be around after JavaScript thread of execution is not busy (the callback function will be waiting in the callback queue to be pulled by the event loop to be handled after a really short time)
function count() {
var counter = 100;
var max = 1000;
function timeoutLoop() {
document.getElementById('cc').innerHTML = counter;
if (++counter < max){
setTimeout(timeoutLoop, 0);
}
}
setTimeout(timeoutLoop, 0);
}
count();
<div id="cc">
</div>
More about the event loop - https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
Great article about browser rendering - https://developpaper.com/the-process-of-browser-rendering-web-pages/
It's because you were using a while loop, instead use an if statement to check whether the counter has reached 1000. See below:
var counter = 100;
function countdown() {
if(counter < 1000) {
counter++;
console.log(counter);
document.getElementById('cc').innerHTML = counter;
}
}
countdown();
setInterval(countdown, 1000);
<div id="cc"></div>
You are not giving the browser time to breathe
Also why have a loop when setInterval loops?
And you want to count down. not up I guess
Also we want to stop the counting
Lastly we can save a bracket
let counter = 10; // 10 to show it works
let tId;
const cc = document.getElementById('cc');
function countdown() {
if (counter === 0) {
cc.innerHTML = "DONE!";
clearInterval(tId); // stop
return
}
// console.log(counter);
cc.innerHTML = counter;
counter--;
}
countdown();
tId = setInterval(countdown, 1000);
<span id="cc"></span>

Clearing an anonymous setInterval

How do you clear an anonymous setInterval function, like the following, so that i stops incrementing?
var i = 0;
setInterval(function(){
console.log(i);
i++;
}, 1000);
You need to store it in variable and then pass that variable in clearInterval.
var i = 0;
let variable = setInterval(function(){
i++;
console.log(i)
}, 1000);
//to clear interval after 5 seconds to check if it works
setTimeout(() => clearInterval(variable),5000)
This is highly NOT recommended!
Nevertheless, you can accomplish this by temporarily monkey-patching the window.setInterval function so you can capture the reference to the timer.
The following is a consolidated example, see further below for an implementation example.
// Declare a variable to store the interval
let rogueInterval = null;
//Override the setInterval method
const oldSetInterval = window.setInterval;
window.setInterval = (...args) => {
rogueInterval = oldSetInterval(...args);
}
var i = 0;
setInterval(function() {
console.log(i);
i++;
}, 1000);
// Reset it
window.setInterval = oldSetInterval;
// Will clear your rogueInterval after 5 seconds
setTimeout(() => {
clearInterval(rogueInterval);
}, 5000);
It sounds like you are including a script via script.src, therefore, you would need to put an inline script tag before to override the setInterval, and an inline script tag after to reset the setInterval:
<script> // JS that overrides the setInterval </script>
<script src="problem-file.js"></script>
<script> // JS that resets the setInterval </script>
Unfortunately, this approach assumes there is only one setInterval within the problem file, and the setInterval is not set asynchronously itself. If you absolutely needed to, you could leave the monkey-patch in place, and check the stringified version of the function being passed in, and if it matches some criteria, then capture it.

Having a hard time with callbacks

Learning about callbacks and the solution to this problem eludes me.
It should print a number every second counting down until zero. Currently, it logs the numbers from 10 - 0 but all at once and continues in an infinite loop.
Please help me to gain a better understanding of this situation. I have read up on callbacks and have a conceptual understanding but execution is still a bit tricky.
var seconds = 0;
var countDown = function(){
for(var cnt = 10; cnt > 0; cnt--){
setTimeout(function(x){
return function(){
seconds++
console.log(x);
};
}(cnt), seconds * 1000);
}
}
countDown()
The way your code is working now, it executes a for loop with cnt going from 10 to 1. This works. On each iteration, it schedules a new function to be run in seconds * 1000 milliseconds, carefully and properly isolating the value of cnt in x each time. The problem is that seconds is 0, and it will only be changed once a callback executes; but by the time a callback executes, all of them will already have been scheduled for execution. If you need seconds * 1000 to vary while you’re still scheduling them all (while the for loop is still running), you need to change seconds in the loop, rather than inside one of the callbacks.
Read up on IIFEs to see how they work. In this situation, you're creating a closure of the value you want to print. You had the right idea, but your syntax was off.
var seconds = 0;
var countDown = function () {
var cnt = 10;
// simplify your loop
while (cnt--) {
// setTimeout expects a function
// use an IIFE to capture the current value to log
setTimeout((function (x) {
// return the function that setTimeout will execute
return function (){
console.log(x + 1);
};
}(cnt)), (++seconds) * 1000);
}
};
countDown();

the counter is doubling

While working on my personal project, I've encountered a problem. The problem is every time my function loops the counter counts twice.
JavaScript Code:
function punch(){
var hit;
var h1=100;
h1-=1;
counter++;
hit=setInterval('punch()',2000);
}
What I wanted it to do is that every 2000 milliseconds the counter goes up 1.
In your original code every time the function punch is called is called again internally.
var counter = 0;
function punch(){
var h1=100;
h1-=1;
counter++;
}
var hit = setInterval(punch,2000);
window.setInterval(function(){
/// call your function here
}, 2000);
Call your function where commented and inside the function increment your counter.
var counter = 0;
var h1=100;
setInterval(punch,2000);
function punch(){
h1-=1;
counter++;
}
Here you go: http://jsfiddle.net/9JLdU/3/
<div id="counter"></div>
<script>
var hit;
var counter = 0;
window.punch = function()
{
var h1=100;
h1-=1;
counter++;
document.getElementById('counter').innerHTML=counter;
}
hit = setInterval('punch()',2000);
</script>
setInterval will cause the function to be called about every 2 seconds until cancelled. By including another call to setInterval within the function, another sequence of calls is established each time it is called, so eventually you'll have thousands of instances running, each incrementing the counter.
So either use one call to setInterval, or have the function call itself using setTimeout, which only runs once. Also, it's preferred to pass a function reference to setInterval and setTimeout as passing a string calls the Function constructor and is effectively a call to eval, which is needlessly expensive in terms of system resources.
var counter = 0;
function punch() {
// ...
counter++;
hit = setTimeout(punch, 2000);
}
punch();
or
var counter = 0;
function punch() {
// ...
counter++;
}
setInterval(punch, 2000);
The advantage of setTimeout is that you can easily vary the delay based on some other logic, or stop the sequence without cancelling the timeout.
Note that when doing:
hit = setInterval(...);
the value of hit is an index that can be used to cancel the interval, it is not the value returned by punch (which is undefined since there is no return statement).
The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds).
The setInterval() method will continue calling the function until clearInterval() is called, or the window is closed.
Read about setInerval() Here
Syntax
setInterval(function,milliseconds)
Working Example here
<script>
var hit = 100;
counter = 0;
var myVar = setInterval(function() {punch()}, 1000);
function punch() {
hit--;
counter++;
}
</script>

JavaScript: how to control progress speed?

Is there any option to increase and decrease the speed of the progress?
Sometimes progress takes time and sometime very slow to finish:
var value = 0,
interval = setInterval(function() {
value = ((+value) + .1).toFixed(1);
if(value == 80.5) clearInterval(interval);
$('p').html(value+'%');
},2);
http://jsfiddle.net/sweetmaanu/zjdBh/13/
You'll note that your code is using setInterval(). This global JavaScript function is used for periodically executing code at a given time interval. It takes two arguments for its typical usage (which is the way you are using it here). It returns a unique ID that can be used to identify your particular interval function (since multiple ones can be set up simultaneously).
The first argument is a function to be executed on the interval. Your function is the anonymous function:
function() {
value = ((+value) + .1).toFixed(1);
if (value == 80.5) clearInterval(interval);
$('p').html(value + '%');
}
This function will increase the percentage progress on each execution.
The second argument is an integer number for the number of milliseconds (thousandths of a second) to let elapse before the function from the first argument is executed. This is the key part for your question, I believe. Your code has 2 (on the last line of your posted code), so it will wait 2 milliseconds before executing your function (which increments the percentage progress), and then it will wait 2 more milliseconds, then execute the same function again, etc.
By simply changing the value of the second argument, you can change how fast or slow your function executes each time, which changes how fast or slow your percentage increases. So if you set it to 500, then setInterval will wait for a half a second before each execution of the function.
You can read about the other JavaScript timer functions here, in particular about clearInterval(), which your code uses in the anonymous function to end the interval when you reach 80.5%.
I hope this helps:
$(function(){
var value1 = 0;
var value2 = 0;
var span1 = $('#val1');
var span2 = $('#val2');
var interval1 = setInterval(function(){
span1.text(++value1);
if (value1 === 80) {
clearInterval(interval1);
clearInterval(interval2);
interval1 = null;
interval2 = null;
span2.text(5);
}
}, 100); // you can change speed here
var interval2 = setInterval(function() {
span2.text(value2++ % 10);
}, 70);
});
HTML:
<body>
<div class="progress-bar"></div>
<hr>
<p><span id="val1">0</span>.<span id="val2">1</span>%</p>
</body>

Categories