Counter not displaying each number, just shows final total - javascript

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>

Related

How to stop a function when it's called?

I'm building a program that either counts down or up and I've got it working however I like to press count-up in the middle of count down or vice versa and I like the counter to stop and count up or vice versa. how do I achieve that? thanks a lot for your help :)
function myFunctionUp() {
var Timer = setInterval(function () {
i++;
document.getElementById("mydata").textContent = i;
if (i >= 21)
clearInterval(Timer);
if (i == 21){
document.getElementById("mydata").textContent = "Boom-up!";
}
}, 1000);
}
function myFunctionDown() {
var Timer = setInterval(function () {
i--;
document.getElementById("mydata").textContent = i;
if (i <= 0)
clearInterval(Timer);
if (i == 0){
document.getElementById("mydata").textContent = "Boom-down";
}
}, 1000);
}
Use a variable to keep track of the way to count. When a button is clicked, invert the value of the variable :
let countDown = 10;
let increment = -1;
function count() {
countDown += increment;
document.getElementById('container').innerText = countDown;
setTimeout(() => count(), 1000);
}
document.getElementById('btn').addEventListener('click', function () {
increment = -increment;
});
count();
Working stackblitz here
You typically never "take control" on the execution of another method. When you want to do that, the logic must be inverted. The function itself must ask if it should continue.
With an example : let's take a function which works in an infinite loop, that you want to be able to stop on demand. In some languages, you could run some code in a thread and interrupt the thread on demand. But even if it is possible, it is generally a bad idea to stop some code at the middle of its execution.
A better way of doing that is to create a "should Continue ?" piece of code at the end of the iteration. It could read a variable or call a method etc. When you want to stop the iteration, you just have to set this variable and you know that the infinite loop will stop graciously at the end of the current iteration

clearTimeout not working: parameter undefined(even though it's defined in the global scope)

My setTimeout() function works, but my clearTimeout() is not working. Even though I have an 'if' statement that's supposed to run the clearTimeout function once my variable 'secs' is less than 0, the timer keeps counting down into negative numbers. When I type my variable name, 'secs' into the console, I get undefined, even though it's defined as a parameter in the function called by my setTimeout. I don't know what I'm doing wrong. Can anyone help, please?
My full code is at https://codepen.io/Rburrage/pen/qBEjXmx;
Here's the JavaScript snippet:
function startTimer(secs, elem) {
t = $(elem);
t.innerHTML = "00:" + secs;
if(secs<0) {
clearTimeout(countDown);
}
secs--;
//recurring function
countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);
}
Add a condition to call recursive function like below.
if (secs < 0) {
secs = secsInput;
}
//recurring function
countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);
For a countdown timer, I would recommend using setInterval and clearInterval instead. setInterval will repeatedly run the callback function for you. It might look like this:
let countdown;
function startTimer(secs, elem) {
countdown = setInterval(function(){
t = $(elem);
t.innerHTML = "00:" + secs;
secs--
if (secs < 0) {
clearInterval(countdown);
}
}, 1000);
}
By the time you call clearTimeout(countDown), countDown refers to the previous timeout, that already timed out. It will not stop the one yet to start. You could just not re set the timeout, like
if(!/*finished*/) setTimeout(startTimer, 1000, secs, elem);
In your case, it's more convenient to use setInterval and clearInterval.
To keep the setTimeout and clearTimeout functions, you should add return in the if statement.
function startTimer(secs, elem) {
t = $(elem);
t.innerHTML = "00:" + secs;
if(secs<0) {
clearTimeout(countDown);
return;
}
secs--;
//recurring function
countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);
}
So there are 4 events in my opinion that will have to be addressed by the timer:
The quiz starts
The quiz ends
The timer runs out
The player answers a question
This can be solved by a function returning an object with some options.
The createTimer can be used to set the parameters for the timer.
Point 1. would be timer.start() --> will start a timer with the parameters
Point 3. can be addressed with the callback that will be called if the timer runs out --> createTimer(5,'display', ()=>{ // your code goes here })
Point 2. can be achieved with --> timer.stop()
Point 4. is needed when the timer needs to be reset without running out timer.reset()
Further on the interval is not in the global scope so you could have multiple timers with different settings and they wouldn't interfere with each other
// function for creating the timer
function createTimer(seconds, cssSelector, callbackOnTimeout) {
// interval the timer is running
let interval;
// the html node where innerText will be set
const display = document.getElementById(cssSelector)
// original seconds passt to createTimer needed for restart
const initSec = seconds
// starting or continuing the interval
function start() {
// setting interval to the active interval
interval = setInterval(() => {
display.innerText = `00:${seconds}`;
--seconds;
if (seconds < 0) {
// calling restart and callback to restart
callbackOnTimeout()
restart()
}
}, 1000);
}
// just stopping but not resetting so calling start will continue the timer
// player takes a break
function stop(){
clearInterval(interval)
}
// opted for a restart and not only a reset since it seemed more appropriate for your problem
function restart(){
clearInterval(interval)
seconds = initSec
start()
}
// returning the object with the functions
return {
start: start,
stop: stop,
restart: restart
}
}
// example for creating a timer
const timer1 = createTimer(5,'display',()=>{
console.log(`you where to slow ohhh...`)
})
// calling the timer
timer1.start()

Using setInterval to Save Form Every 60 Seconds Not Working

I'm working on some code that'd I'd like to have each loop run every 60 seconds, but currently each loop runs immediately. The purpose of the code it to see if a form has changed, and if it has save the form. Do I have setInterval setup incorrectly?
function saveHelper(formId) {
for(var i = 0; i < 4; i++) {
save(formId);
}
}
function save(formId) {
console.log('might save');
var changed = formChanges(formId);
var intId = setInterval(stall, 60000);
if(changed.length > 0) {
console.log('would save');
//document.getElementById(formId).submit();
}
clearInterval(intId);
}
function stall() {
return true;
}
You are treating interval as some sort of synchronous sleep method, which is not the case. The change code should be inside of the setInterval, it should not live after the interval.
var intId = setInterval(function () {
if(changed.length > 0) {
console.log('would save');
//document.getElementById(formId).submit();
}
}, 60000);
setInterval doesn't pause your code, it just schedules some code to be run some time in the future. For example, when you do this:
var intId = setInterval(stall, 60000);
That says "every 60000 milliseconds, run the function stall". As soon as this line of code completes, it will immediately run your next line of code, do the saving, then clear the interval. Clearing the interval cancels it, so now nothing will happen in 60000 milliseconds.
Instead, you'll want to do something like this:
function saveHelper(formId) {
let count = 0;
const intId = setInterval(function () {
if(changed.length > 0) {
console.log('would save');
//document.getElementById(formId).submit();
}
count++;
if (count === 4) {
clearInterval(intId);
}
}, 60000);
}
Every 60000 milliseconds, the inner function will run, and do the saving. After saving, it checks how many times we've done this, and once it reaches 4, it clears the interval to stop it from happening any more.

Resetting Timer Errors - Javascript

I am trying to create a one-minute timer that runs twice. During the first run, the timer will countdown to 0. Then, the timer will reset to one minute and start the countdown again. To create this timer, I am using Javascript, which is a programming language that I am not particularly skilled at.
The timer works when I use it just once. However, when I try to use it in a for loop, create a recursive function, or even run it twice in a row by calling the function twice, the countdown is not consecutive. For example, it will display 4, then 2, then -1, even though the countdown is supposed to be consecutive and end at 0.
I have searched on StackExchange to find similar questions. I followed the answer to this question, but the countdown displayed NaN instead of the proper numbers. I have also read through a number of other questions, but their answers have not worked for me.
My Javascript code is:
window.onload = function() {
var seconds = 60;
function timeout() {
setTimeout(function () {
seconds--;
document.getElementById("time").innerHTML = String(seconds)
if (seconds > 0){
timeout();
}
}, 1000);
}
timeout()
seconds = 60;
timeout()
};
document.getElementById("time") refers to an empty paragraph with time as its ID.
Thank you in advance.
Your code is running the function twice at the same time. Try this, setting a separate counter, and stopping the timer once the count has reached a set number:
window.onload = function() {
var seconds = 60;
var count = 1;
function timeout() {
setTimeout(function() {
seconds--;
document.getElementById("time").innerHTML = String(seconds)
if (seconds > 0) {
timeout();
} else {
seconds = 60;
count++;
if (count <= 2) {
timeout();
}
}
}, 1000);
}
timeout();
};
<p id="time"> </p>

Why isn't clearInterval working in this code?

There is a function which sets an interval using setInterval(), but even after calling clearInterval(), I can see in the console that the else condition is still running. How can I clear that interval properly?
function increase(old, step, neu) {
var i = 0;
var delay2;
function countUp() {
if (i < 5) {
old += step;
// console.log("increase")
$("#total-price-value").text(old + " dollors");
$("#total-price-value").digits();
i++;
delay2 = setInterval(countUp, 80);
} else {
clearInterval(delay2);
console.log(delay2);
}
}
countUp();
}​
It looks like you're a little confused about the difference between timeouts and intervals. Timeouts fire only once; intervals fire many times. If you're using an interval, you probably only want to set it once (you're setting it every time). If you're using a timeout, you probably want to set it every time (like you're doing).
In order to fix the problem, you'll either want to switch to timeouts (probably the easiest; just a search/replace) or only set the interval once.
For example, here is how one might use setTimeout to count up to five:
var count = 0;
function timeoutFired() {
count++;
if(count < 5) {
setTimeout(timeoutFired, 1000);
}
}
setTimeout(timeoutFired, 1000);
Using timeouts, we don't need to clear to stop it from counting; simply not setting a timeout will prevent it from running again.
Here is how one might use setInterval:
var count = 0;
function intervalFired() {
count++;
if(count >= 5) {
clearInterval(interval);
}
}
var interval = setInterval(intervalFired, 1000);
If you want some code running periodically using intervals to stop, you must call clearInterval. Note that we only call setInterval once, versus setTimeout every time we didn't want it to continue.
Apparently, you have mistaken setInterval for setTimeout. setInterval runs the enclosed function every n milliseconds while setTimeout executes only once after n milliseconds.
I suppose you wanted to "tick until 5" so here's a sample:
function increase(old, step, neu) {
var i = 0;
interval = setInterval(function() {
if (i < 5) {
//do something at this "tick"
console.log(i);
i++;
} else {
//else, stop
clearInterval(interval);
}
},80);
}
increase();

Categories