Repeated use of setTimeout in JavaScript refreshes the page - javascript

I am in the process of building a basic timer using HTML, CSS, and JavaScript.
Currently the timer accepts minutes and seconds as output and once the timer is done, the user is alerted. There is no way of seeing progress at the moment but I do plan on adding it once I've solved my problem.
When the start button is clicked, the JavaScript function startTimer is called, which calculates at what time (hours, minutes, seconds) the timer will finish and stores these values in an array. If one of the values goes past it's maximum (eg seconds goes past 59) then the maximum will be subtracted and 1 will be passed onto the next item in the array (in my example, minutes). Another function, updateTime, is called, with the finish time array passed as a parameter.
updateTime gets the current hours, minutes, and seconds and stores them in an array, before comparing them to the finish array. If they are equal, the timer must be finished, so the user is alerted the time is up and that is that. If they aren't equal, setTimeout is called to execute updateTime again passing in the finish time after 1000 milliseconds (1 second).
When I run my webpage and specify a time and click start, the page simply refreshes.
Code:
timer.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Timer</title>
<script src="script.js"></script>
</head>
<body>
<form>
<label for="minutes" id="minutes-label">Minutes</label>
<input id="minutes" type="number" min="0" max="59" value="0"/>
<label for="seconds" id="seconds-label">Seconds</label>
<input id="seconds" type="number" min="0" max="59" value="0"/>
<br></br>
<button onclick="startTimer()">Start</button>
</form>
</body>
</html>
script.js
function updateTime(f) {
let d = new Date();
let current = [d.getSeconds(),d.getMinutes(),d.getHours()];
if (current === f) {
alert("Time is up!");
}
else {
setTimeout(updateTime,1000,f);
}
}
function startTimer() {
let increaseSecs = parseInt(document.getElementById("seconds").value);
let increaseMins = parseInt(document.getElementById("minutes").value);
let d = new Date();
let finish = [d.getSeconds()+increaseSecs,d.getMinutes()+increaseMins,d.getHours()];
if (finish[0] >= 60) {
finish[0] -= 60;
finish[1] += 1;
}
if (finish[1] >= 60) {
finish[1] -= 60;
finish[2] += 1;
}
updateTime(finish);
}
The updateTime function should be executed every second until the current and finish arrays match, indicating the time is up, at which point the user is alerted that the timer has finished.
If I add console.log each time the current array is compared to the finish array, the log is written to once before the page refreshes.
I've also replaced setTimeout with setInterval but the problem remains.

Thanks to the people who commented telling me the problem was that my start button was set to submit by default. Indeed, after changing the button type to "button", the page no longer refreshed. However, nothing happened so I began to add some console.log lines to see the boolean result of my if statements and as it turns out, JavaScript cannot compare arrays using the equality operator (===), and instead must compare each item of the array individually. To solve this problem, I added in an extra function.
function arrayIsEqual(arr1,arr2) {
let equal = true;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
equal = false;
break;
}
}
return equal;
}
Implementing this into my if statement, I successfully ran the timer multiple times, trying different minutes and seconds combinations.

Related

Creating a Countdown with JavaScript

I am trying to make a Countdown that just log in the terminal the seconds remaining. It should be an interval of 1 second between every log. It has to be as a method of an object. I donĀ“t know if it's because of the scope but somehow it's not working after many trials and code-rewriting.
Anybody can help me with this?
var Countdown = function(seconds) {
this.counter = seconds;
this.start = function() {
setTimeout(
function() {
while (this.counter >= 0) {
console.log(this.counter);
this.counter -= 1;
}
},1000)
}
}
I would use a setInterval() for a simple countdown timer. I would also write my function for the math loop outside of the setInterval and then call on the function within the interval, like the following => setInterval(timerFunction(), 1000). There is no need for a loop when you use the interval, it does the looping each defined time increment as set in your setInterval(). Each time the interval fires, the function will do its thing.
EDIT: added a conditional to see if the interval time has run out.
I have included an example of a simple count down timer in my answer below along with notation inside the code that helps to explain further. Hope this helps.
Also, by terminal, I assume you mean the console? My example displays the setInterval in the console...
let sMin = 2; // amount of minutes you wish to start with
let time = sMin * 60; // format for minutes by multiplying by 60 as we have 60 seconds in each minute
let countdown = setInterval(update, 1000) // set up a setInterval for the countdown function
// create a function that will countdown the seconds
function update() {
// define our minutes using Math.floor(time / 60)
let min = Math.floor(time / 60);
// define our seconds by modulating time with 60, our seconds units
let sec = time % 60;
// tenerary conditional to see if seconds is set to 0 for proper display of formatting as seconds
sec = sec < 10 ? '0' + sec : sec;
// display the countdown timer in time format using the minutes and seconds variables
console.log(`${min}:${sec}`);
// decrement time by one second with each interval as set in the setInterval call `1000`
time--;
// clear the interval if the minutes and seconds are both set to 0
min == 0 && sec == 0 ? clearInterval(countdown) : countdown;
}
Yes it was because of the scope. As you are using this inside setTimeout() it uses the global scope.
var Countdown = function(seconds) {
this.counter = seconds;
this.start = function() {
setTimeout(
function() {
while (this.counter >= 0) {
console.log(this.counter);
this.counter -= 1;
}
}.bind(this),1000)
}
}
I'm using bind to set "this" to current context.
And with reference to your question about timeout, instead of using setTimeout() use setInterval() to achieve your need about log with respect to seconds
function countDown(whileCountingDown, forHowLong, whenFinishedThen){
//error handling begin(for user's understanding)
if(arguments.length<3){return RangeError("ALL three arguments must be used")}
var typeErrors=[]
if(typeof whileCountingDown!="function"){typeErrors.push("whileCountingDown MUST be a function")}
if(typeof forHowLong!="number"){typeErrors.push("forHowLong MUST be a number(and it represents seconds)")}
if(typeof whenFinishedThen!="function"){typeErrors.push("whenFinishedThen MUST be a function")}
if(typeErrors.length>0){return TypeError(`There are ${typeErrors.length} parameters that are incorrect data types\n\n${typeErrors.join('\n')}`)}
//error handling begin(for user's understanding)
//........................................................................................................................
//the part that matters to you once you enter correct stuff
var i=setInterval(()=>{forHowLong--
if(forHowLong<=0){//count finished, determine what happens next
clearInterval(i); whenFinishedThen()
}
else{whileCountingDown(forHowLong)}//do this for each second of countdown
},1000)
}
console.log("The timers in the console and on the html element are 2 DIFFERENT countdowns")
//example use
countDown((m)=>{console.log(`${m} seconds left`)}, 30, ()=>{console.log('Cheers, the countdown is OVER')})
//obviously you can do stuff like edit randomHTML-Element.innerText for each second of the countdown or anything as you so desire since what i made is kindof flexible
//..........................................................................................................................
//more examples
//now for some fun stuff, we're gonna be editing an html structure, but first, we're going to make a 'timeParse' function to make it look kind of elegant
function timeParse(seconds){
//yup, error handling begin
if(typeof seconds!="number"){return TypeError("The parameter 'seconds' MUST be a number")}
//yup, error handling end
//below is the stuff to look at
var timeArr=[seconds]
if(timeArr[0]>=60){//if seconds >= 1 minute
timeArr.unshift(Math.floor(timeArr[0]/60))
timeArr[1]=timeArr[1]%60
if(timeArr[0]>=60){//if minutes >= 1 hour
timeArr.unshift(Math.floor(timeArr[0]/60))
timeArr[1]=timeArr[1]%60
if(timeArr[0]>=24){//if hours >= 1 day
timeArr.unshift(`${Math.floor(timeArr[0]/24)}d`)
timeArr[1]=timeArr[1]%24
}
}
}
return(timeArr.join`:`)
}
//now for applying countDown to things other than the console
function countDownAgain(){//just something that will show the flexibility of what i made.. im going above and beyond because i wanna look back on my answers as notes on how to do things(also ez copy pasting for future me xD)
countDown(
(s)=>{document.getElementById('toTime').innerText="Second Count "+timeParse(s)},
86401,
()=>{document.getElementById('toTime').innerText="No way you waited that long LOL"}
)
}
countDown(
(s)=>{document.getElementById('toTime').innerText="First Count "+timeParse(s)},
100,
countDownAgain
)
<div style="background-color:red;height:100px;text-align:center;line-height:50px"><h1 id="toTime">Count Down Time :}</h1></div>

How to make timer reach certain value after specific amount of time?

Okay, i made a simple timer and i want to reach certain value after some time. Let's say it starts from 100 and it need to reach 300 in 2 mins and in the meantime it increments and decrements by 5 for example and keeps up to create the illusion that it's random and not just straightforward incrementation. In the end it will reach 300 for the same time. Similar to social blade real time subscribing. It adds and removes certain amount of subscribers because people subscribe and unsubscribe but here it will reach the end value in 2 or 5 min.
let count = 0;
let end = 300;
function increment() {
if (count < end){
count++;
}else if(count >= end)
clearInterval(count);
document.getElementById("num").innerHTML = count;
}
setInterval(increment, 1000);
<html>
<body>
<h2 id="num"></h2>
</body>
</html>
I solved this problem.
function subscribeEmu (sub, unsub, startCount, time);
takes 4 parameters:
sub - number of subscribers
unsub - the number of unsubscribed
counter start value
time - duration in milliseconds
here you can run.
thank you!

Javascript Self Adjusting Count-Down Timer

I am trying to create an accurate countdown timer (accurate to the second), so that the second timer changes every second as opposed to lagging behind due to some other code I have.
I have a very limited understanding of how this works and I have attempted the following:
var seccount=100;
var seccounter=setInterval(sectimer, 1000);
var start = new Date().getTime();
function sectimer() {
seccount--;
elapsed = Math.ceil(seccount/100);
var diff = (new Date().getTime() - start) + seccount;
window.setInterval(sectimer, (0 + diff));
if (seccount < 0) {
return;
}
document.getElementById("sectimer").innerHTML=seccount+" seconds left!"
}
However, this timer seems to skip a few numbers some times. Is there any way to fix this? What am I missing?
EDIT:
Any count-down timer that is more accurate will do. I have been experimenting with the following timer that I have to try and make it more accurate, but I am not having much luck. Basically, it counts down every 1.1 seconds about (instead of every 1 second),
var seccount=100;
var seccounter=setInterval(sectimer, 1000);
function sectimer() {
seccount--;
if (seccount < 0) {
return;
}
document.getElementById("sectimer").innerHTML=seccount+" seconds left!";
}

Skip a setInterval every X loop?

I have a function that gets triggered every 10 seconds with a setInterval(); loop, and I'd like it to skip a call every 60 seconds. So the function would be executed at 10s, 20s, 30s, 40s and 50s but wouldn't be called at 60s, then gets called at 70s and so on.
Is there any straightforward way to do this, or do I have to tinker with incrementing a variable?
Thanks!
Do like this, use the simple modulo math and a counter.
var count = 0;
var interval = setInterval(function(){
count += 1;
if(count % 6 !== 0) {
// your code
}
}, 10000);

How to produce a time delay in JavaScript for a chat App?

I'm currently a beginner at JavaScript and predominantly code in Java.
My Question is is regarding invoking the document.write("string here") periodically (every 1/2 seconds) to append any new unprinted chat message to the client. I earlier tried using the following code :
<html>
<body onload="yantra();">
<script type="text/javascript">
x = 0;
function yantra(){
document.write("Hello<br>");
i = 1;
for(i = 0; i < 100; i++){
setTimeout("writeOneNum()", 1000);
}
}
function writeOneNum(){
x =x + 1;
document.write(x+"<br>");
}
function blank(){}
</script>
</body>
</html>
Instead of it printing 1 to 100 every 1000 millisecond as I expected it to print; in actuality, it printed 1 to 100 at one go (meaning without any delay).
Well, you are setting all the timeouts at once, so of course it fires them all at once. Your code will work with small modification to the loop:
function yantra(){
document.write("Hello<br>");
i = 1;
for(i = 0; i < 100; i++){
setTimeout("writeOneNum()", 1000 * i);
}
}
By multiplying the time with i, the first is fired instantly, the second at 1000 * 1 = 1000 ms, the third at 1000 * 2 = 2000 ms etc.
In your case, it could be wiser to consider the setInterval function:
function yantra(){
document.write("Hello<br>");
setInterval("writeOneNum()", 1000);
}
That will fire the writeOneNum() every second infinitely. To stop the interval at some point, take a look at clearInterval on that same link above.

Categories