Reputation: 49
I'm trying to create a 'Pomodoro' timer that takes user input and creates a timer based on how long somebody wants to use it for (for no reason other than to learn and use it for myself).
I'm finding that my for
loops aren't behaving as I'd expect them to and when you look at the timer itself, it is counting down every second, however the timer itself actually reduces by 6 seconds for every one second counted.
I also can't seem to get the timer to move on to the next bit once it hits zero.
I did originally have breaks in the function so that it would move from the current time to the rest time but that didn't seem to do the trick.
In terms of the 6 seconds problem, I'm not even sure where to begin with that.
// set up a counter for how many times you want to set the pomodoro for - users will input how many cycles they want the program to go through.
const pomodoroQuestion = prompt("How many times would you like to use the pomodoro (1 Pomodoro = 3x 25 minute working burst, 2x 5 minute breaks and 1x 15 minute break)");
const pomodoroLength = parseInt(pomodoroQuestion);
for (let i = 0; i < pomodoroLength; i++) {
function startTimer() {
const currentTime = document.getElementById('pomodoroClock').innerHTML;
const timeArray = currentTime.split(/[:]+/);
let minutes = timeArray[0];
let seconds = secondsTimer((timeArray[1] - 1));
if (seconds === 59) {
minutes = minutes - 1;
}
if (minutes < 0) {
alert("Time's up");
}
document.getElementById('pomodoroClock').innerHTML = `${minutes}:${seconds}`;
setTimeout(startTimer, 1000); // Make the function countdown each second
}
// cycle through the seconds
function secondsTimer(sec) {
if (sec < 10 && sec >= 0) {
sec = `${0}${sec}`;
}
if (sec < 0) {
sec = 59;
}
return sec;
}
// the following loop will be what starts the actual pomodoro cycle.
for (let x = 0; x < 3; x++) {
// function starting a countdown timer for 25 minutes
document.getElementById('pomodoroClock').innerHTML = `${25}:${00}`;
startTimer();
if (x < 2) {
// this is where you're going to perform the function that'll allow for a 5 minute break
document.getElementById('pomodoroClock').innerHTML = `${05}:${00}`;
startTimer();
} else {
// this is where you're going to perform the function that'll allow for a 15 minute break
document.getElementById('pomodoroClock').innerHTML = `${15}:${00}`;
startTimer();
}
}
} // end pomodoroLength loop
<div id="pomodoroClock" class="timer"></div>
<script src="script/script.js"></script>
Where am I going wrong with this one? I feel like I'm just missing a few key pieces of understanding with projects like this, hence creating little practice projects to improve.
Upvotes: 0
Views: 253
Reputation: 338326
I think it's worthwhile to change your approach. What if you had a stand-alone countdown()
function that displays minutes and seconds in a given target element, and notifies you when it's done?
That's easy to do with promises. You make a function that returns a new Promise
, and you resolve()
that promise when the time hits zero:
function countdown(minutes, seconds, targetElement) {
return new Promise(resolve => {
const tick = setInterval(function () {
// count down, display current time in targetElement
if (/* time's up */) {
// stop interval, call resolve()
}
}, 1000);
});
}
And since this function returns a promise, it becomes straightforward to chain multiple of those functions with async
/await
:
async function countdownSequence(...timers) {
for (let t of timers) {
await countdown(0, t, document.getElementById('target'));
}
alert('done!');
}
countdownSequence(5, 10, 5); // counts 5, 10, and 5 seconds, and then alerts 'done!'
Full implementation with a few extras. Note that for the sake of the example, instead of using your sequence 25, 5, 25, 5, 25, 15
for each round, I'm using 5, 2, 5, 2, 5, 3
, and I'm using the seconds
slot of the countdown
function.
function countdown(minutes, seconds, targetElement) {
const pad = num => (num < 10 ? '0' : '') + num;
const display = () => targetElement.textContent = pad(minutes) + ':' + pad(seconds);
return new Promise(resolve => {
const tick = setInterval(function () {
seconds--;
if (seconds < 0) {
minutes--;
seconds = 59;
}
if (minutes < 0) {
clearInterval(tick);
resolve();
}
display();
}, 1000);
display();
});
}
async function pomodoro(numCycles, targetElement) {
targetElement.classList.add('active');
for (let i = 0; i < numCycles; i++) {
targetElement.classList.remove('work');
for (let minutes of [5, 2, 5, 2, 5, 3]) {
targetElement.classList.toggle('work');
await countdown(0, minutes, targetElement);
}
}
targetElement.classList.remove('active');
}
async function start() {
const cycles = parseInt(prompt("How many times would you like to use the pomodoro (1 Pomodoro = 3x 25 minute working burst, 2x 5 minute breaks and 1x 15 minute break)"), 10);
if (cycles > 0) {
await pomodoro(cycles, document.getElementById('pomodoroClock'));
alert("Finished!");
}
}
start();
#pomodoroClock {
display: none;
}
#pomodoroClock.active {
display: block;
color: blue;
}
#pomodoroClock.work {
color: green;
}
#pomodoroClock::after {
padding-left: 5px;
content: '(pause)';
}
#pomodoroClock.work::after {
padding-left: 5px;
content: '(work time)';
}
<div id="pomodoroClock"></div>
Upvotes: 1