Return in setInterval()

Return in setInterval()
0.0 0

#1

@John-freeCodeCamp here

I’m not bypassing a ban. Just can’t login through github because it’s blocked on our school device.

I’ve been typing this throughtout the day by the way.

I posted this on stackoverflow, and as expected, just got disliked when people can’t awnser and try to call it a duplicate while linking me to a mostly unrelated topic.

This is just a basic clock. If you want to play around with the functionality, go to —> https://repl.it/@John_Nicole/Clock

Not totally the same, but will show you a base of what the code is doing. I stop instead of return. If you look closely, the code is really simple, just takes up a lot of space and is repetive.

Now i have some code. All it does is count down from a given time:

function clock(hours, minutes, seconds) {
      var interval = setInterval(function(){ 
      hours = Number(hours)
      seconds = Number(seconds)
      minutes = Number(minutes)
      if (hours === 0 && minutes === 0 && seconds -1 < 0) {
         return 1
      }
        $("#stop").on('click', function() {
           clearInterval(interval)

        })
      if (minutes === 0 && seconds-1 < 0) {
         if (hours < 10) {
          hours = "0"+hours
        }
          // 24:00.000 - 1 second
           hours-=1
          minutes = 59
          seconds = 59
          time = hours+":59:59"
        console.log(hours, minutes, seconds)
      } else if (minutes > 0 && seconds -1 < 0) {
          // 24:37.00 - 1 seconds
        if (hours < 10) {
          hours = "0"+hours
        }
         if (minutes < 10) {
              minutes = "0"+minutes
          }
           minutes -=1
          seconds = 59
        console.log(hours, minutes, seconds)
      } else {
          // 24:37.49 - 1 second
        if (hours < 10) {
          hours = "0"+hours
        }
         if (minutes < 10) {
              minutes = "0"+minutes
          }
          seconds-=1
          if (seconds < 10) {
              seconds = "0"+seconds
          }
          console.log(hours, minutes, seconds)
      }
  }, 1000);
    }

Now if i say console.log(clock("01", "02", "00")) i get undefined. If you look in the code it shows:

if (hours === 0 && minutes === 0 && seconds -1 < 0) {
             clearInterval(interval)
             return 1
          }

Basically when the time is 0, it should return 1. When i console.log() this function, it just returns undefined and starts the clock. This is instead of doing the function than returning. I am stopping the setInterval() than returning. Even without that it’s the same result.

Is there any idea how i can return in a setInterval and not get undefined after period of time? I am stopping the setInterval() than returning.


#3

With the direct question being addressed, I also wanted to show you how I recently solved the same problem. I needed something in JavaScript that could act like a timer, counting down for a specific length of time, and execute a callback when the clock is finished. I also needed a callback for every time the clock “ticks” (every seconds that passes). Anyway here’s what I came up with:

/**
 * Expiration is a countdown utility function
 */
var Expiration = class {
  
  constructor(duration) {
    this.duration = duration;   
    this.count = 0;
  }

  increment() {
    this.count++;
    if (typeof this.oncount === 'function') {
      this.oncount();
    } 
    if (this.count === this.duration && typeof this.oncomplete === 'function') {
      this.oncomplete();
    }
    if (this.count === this.duration) {
      this.count = 0;
      this.stop();
    }
  }
  
  start() {
    this.interval = setInterval(() => this.increment(), 1000);
  }

  stop() {
    clearInterval(this.interval);
  }
  
  toArray() {
    var remaining = this.duration - this.count,
        h = parseInt(remaining/3600).toString().padStart(2,'0'),
        m = parseInt(remaining%3600/60).toString().padStart(2,'0'),
        s = parseInt(remaining%3600%60).toString().padStart(2,'0');
    return [h,m,s];
  }
  
  toString() {
    return this.toArray().join(':').replace(/00:/g,'');
  }
  
}

//How to use the above class
var oneMinute = 60;
var countdown = new Expiration(oneMinute*5);
countdown.oncount = function() {
  console.log(countdown.toString());
}
countdown.oncomplete = function () {
  console.log('Countdown finished, 5 minutes have passed!');
}
countdown.start();

#4

well i wanted to do variable+=clock(...)

Little confused with your code, don’t feel like i’m too that level.


#5

Also, using setTimeout instead of setInterval would fix the issue. Basically, set a timeout with a timeout of a second. If the condition is met, return. If not, tick the clock and call setTimout recursively. This is generally what you want for clocks because it also allows you to adjust the time when it goes out of sync (which setInterval does not). Recursive setTimeouts are generally always the better option, setInterval isn’t great.


#6

I think you should approach the problem from a new angle.

You could use something like this as a base:

var seconds = 0;
var maxSeconds = 60*5; //Five minutes
function increaseTime() {
    seconds++;
    console.log(seconds);
    if (seconds === maxSeconds) {
      clearInterval(intervalID);
    }
}
var intervalID = setInterval(increaseTime, 1000);

EDIT: I almost forgot, you can extract the hours and minutes that have passed based on how many seconds have passed. For me, this made the whole process of making a countdown clock much easier.

The code goes like this:

var hours = parseInt(seconds/3600),
mins = parseInt(seconds%3600/60),
secs = parseInt(seconds%3600%60);

#7

@DanCouper @cmoss3

Little confused on what you guys are talking about. How would i add to my code or change little to make it work?

Still not understanding the whole concept of comparing the seconds and stuff.


#8

Yeah, you can disregard my first post about comparing the seconds, minutes and hours.
You are actually already comparing hours, minutes and seconds correctly.
That was an oversight on my part. Sorry.

Also, you are not going to be able to return from within the interval callback like you’re currently trying to do. This just won’t work. That’s why I’m suggesting that you take a new approach all together. Not only that, but you can accomplish what you’re trying to do with far less code.
Something you should do to improve your code is stop manually tracking hours, minutes and seconds. You only need to keep track of seconds.

Here is a functional example of what I’m talking about. At the bottom of the code, there’s an example of how to use the function. It’s basically what you’re already doing, except you don’t pass hours, minutes and seconds; you only pass seconds. Again, no need for the extra complexity.

function startTimer(maxSeconds) {
  var seconds = 0;
  var intervalID = setInterval(function() {
    
    seconds++;
    
    var timeRemaining = maxSeconds - seconds,
        hours = parseInt(timeRemaining/3600),
        mins = parseInt(timeRemaining%3600/60),
        secs = parseInt(timeRemaining%3600%60);
    
    console.log(hours + ':' + mins + ':' + secs);
    
    if (seconds === maxSeconds) {
      clearInterval(intervalID);
    }
    
  }, 1000);
}

//Here is an example of how to use the above function
startTimer(60 * 60 * 3);