repeating timer functionality and logic - javascript

I'm creating pomodoro timer- interval should repeat with different duration after first one completes. simplified non working exampe:
var firstDuration=5;
var secondDuration=10;
var timer=setInterval(()=>{
firstDuration--
if (firstDuration<0){
clearInterval(timer) ..
//secondDuration-- dont know how to continue..
What is the best way to implement such functionality? Also i plan to use Date.now() rather than -- .

If i've understood the requirements correctly, this will do what you want. It will have a timer go off every second until 20 minutes have elapsed, then every second until 5 minutes have elapsed. At that point it starts over with the 20 minute countdown.
const workDurationSeconds = 20 * 60;
const breakDurationSeconds = 5 * 60;
function startCountdown(session) {
let duration;
if (session === 'work') {
duration = workDurationSeconds;
} else {
duration = breakDurationSeconds;
}
let id = setInterval(() => {
duration--;
if (duration <= 0) {
clearInterval(id);
startCountdown(session === 'work' ? 'break' : 'work');
}
}, 1000);
}

Related

javascript countdown timer

I want to create a countdown timer with javascript that will count down every six minutes. When it gets to 00 I will start from 6 minutes. It will continue like this forever. If the browser is refreshed, this countdown will continue. Even if the browser is refreshed, the countdown will not start again from 6 minutes until 00. How can I do this? Someone help with the code.
Welwome to SO. Please, before asking for help try to provide some code before.
For this time, we will help.
let countdown = 6 * 60;
setInterval(function() {
countdown--;
if (countdown === 0) {
countdown = 6 * 60;
}
document.getElementById("countdown").innerHTML = countdown;
}, 1000);
Note that if the browser is refreshed, everything will reinitialize.
To keep track, you'll need a database or store in client browser.
Make a button with the onclick function starting the timer using the setInterval function that has a callback that decreases a second each second from the 6 minutes.In the callback, store the time into localstorage, and make the startingTime value restore from the localstorage time value if the localstorage time value is not 0.
const start = document.querySelector("#start")
const timeP = document.querySelector("#time")
let interval;
const startingTime = 360
let time = startingTime || window.localStorage['time']
console.log(window.localStorage['time'])
const setLocalStorage = () => {
console.log(time);
window.localStorage['time'] = time}
if (time <= 0) {
time = startingTime
setLocalStorage()
}
function calc(s) {
minutes = (s - s % 60) / 60;
seconds = s % 60;
return minutes + ":" + seconds
}
function callback() {
console.log(time);
time--;
timeP.innerHTML = calc(time);
if (time <= 0) {
time = startingTime;
clearInterval(interval);
start.classList.remove("invis")
timeP.classList.add("invis")
}
setLocalStorage();
}
function startTimer() {
interval = setInterval(callback, 1000);
start.classList.toggle("invis");
timeP.classList.remove("invis")
}
start.onclick = startTimer
.invis {
display: none
}
#start {
color: black;
background-color: red;
}
#time {
color: black;
}
<button id="start">START</button>
<p1 id="time" class="invis"></p1>
If you want the timer "not to pause" to run even after you exit the browser then:
you could store the value of Date.now() in localstorage or wherever you want
and get the value on load and subtract that value from the current Date.now() and you have the difference between the times now you can use that difference to do what you want.

How can i get counter from setInterval?

I have interval that needs to do some http requests after one minute
setInterval(() => {
this.takeTableDataCallInterval();
}, 60000);
How can i get counter minus from my Interval Number ?
For example every one second i want to show something like
60 seconds Left until new call is maked
59 seconds Left until new call is maked
When it comes to 0 it should start over
Here is an example:
it works every one second in order to do the countdown but once it reach to the 60 it resets the countdown and does the request.
const timer = document.querySelector('#timer');
let counter = 60;
setInterval(() => {
if (counter === 0) {
//this.takeTableDataCallInterval();
counter = 60;
}
else {
timer.innerHTML = `${counter} seconds left`;
counter--;
}
}, 1000);
<p id="timer"></p>
Counting shorter setInterval periods is one way of doing this, although timings here are rarely accurate enough to decently measure the passage of time, and you'll see drift (i.e. 60 one second intervals won't sum to exactly 60s)
Instead, record a "due time" with a high accuracy using performance.now()
let dueTimeMs = performance.now() + 60000;
then set an interval with relatively short time
setInterval(() => {
const nowMs = performance.now();
const timeUntilDueMs = dueTimeMs - nowMs;
// report remaining time
if(timeUntilDueMs <= 0){
// do something
dueTimeMs += 60000;
}
},100);
Try this:
let timeout;
function resetTimeout(limit) {
timeout = limit;
}
function serviceCall() {
console.log('Service call made')
}
setInterval(() => {
if(timeout == 0 || timeout == null) {
(timeout == 0) ? serviceCall() : ''
resetTimeout(60);
}
console.log(`${timeout}s left until new call is made`)
timeout --;
}, 1000);

Cant Make a function run again

I made a timer that will reach zero.
and when it reaches zero make the timer run again.
the timer goes back to the starting number but doesnt run again.
also when i call it again the numbers just start to jump.
the code:
var timerPlace = document.getElementById('timer');
var timerP = document.getElementById('timerHard');
var stopTimer;
var toStop;
function timeMed() {
console.log('im in!')
var counter = 0;
var timeLeft = 5;
timerPlace.innerHTML = '00:45';
function timeIt() {
console.log('here')
counter++
timerPlace.innerHTML = convertSeconds(timeLeft - counter);
if (timerPlace.innerHTML == '00:00') {
clearInterval(stopTimer);
resetExercise();
timeMed();
}
}
function convertSeconds(s) {
var sec = s % 60;
var min = Math.floor((s % 3600) / 60);
return ('0' + min).slice(-2) + ':' + ('0' + sec).slice(-2);
}
if (!stopTimer) {
stopTimer = setInterval(timeIt, 1000);
}
}
You only call setInterval() when stopTimer is not set. But after the countdown completes, stopTimer is still set to the ID of the old interval timer, so you don't restart it. You should clear the variable when you call clearInterval().
if (timerPlace.innerHTML == '00:00') {
clearInterval(stopTimer);
stopTimer = null;
resetExercise();
timeMed();
}
Modern ES6 Approach and best practices.
I've decided to take the chance and refactor your code a little with Javascripts best practices in mind.
I've added comments which explain the code, and the engineering considerations.
The baseline for the timer is taken from the excellent answer here: https://stackoverflow.com/a/20618517/1194694
// Using destructuring on the paramters, so that the keys of our configuration object,
// will be available as separate parameters (avoiding something like options.duraitons and so on.
function startTimer({duration, onUpdate , infinite}) {
let timer = duration, minutes, seconds;
let interval = setInterval(function () {
minutes = parseInt(timer / 60);
seconds = parseInt(timer % 60);
// you can also add hours, days, weeks ewtc with similar logic
seconds = seconds < 10 ? `0${seconds}` : seconds;
minutes = minutes < 10 ? `0${minutes}` : minutes;
// calling your onUpdate function, passed from configuraiton with out data
onUpdate({minutes, seconds});
if (--timer < 0) {
// if infinite is true - reset the timer
if(infinite) {
timer = duration;
} else {
// Clearing the interval + additonal logic if you want
// I would also advocate implementing an onEnd function,
// So that you'll be able to decide what to do from configuraiton.
clearInterval(interval);
}
}
}, 1000);
}
const duration = 5;
const displayElement = document.querySelector("#timer");
startTimer({
duration,
onUpdate: ({minutes, seconds}) => {
// now you're not constraint to rendering it in an element,
// but can also Pass on the data, to let's say your analytics platform, or whatnot
displayElement.textContent = `${minutes}:${seconds}`;
},
infinite: true
});
<div id="timer">
</div>

Continuing a cleared setIntervall instead of resetting it

EDIT & UPDATE: for reference I rewrote the whole thing with only 1 timer and a second to time converter. Very clean and less complex. Here is the full code: http://pastebin.com/Hb6cBryL
I got this timer that I built out of javascript: http://powerpoint.azurewebsites.net/
It is quite simple code, but for the final implementation I would need to be able to pause the timer and restart it. I use 2 setIntervalls, 1 for the minutes that triggers every 60s and one for the seconds that triggers every second.
When I pause it I clear the intervals. However when I restart them the minutes restart at the 60 interval and aren't synced with the seconds anymore.
I probably implemented this in a horribly wrong way so I'd like to ask for your advice. 1 idea I had was to continue the inverval but avoid updating the variable and text on the page so that the minutes/seconds stay in sync< However this doesn't sound like an ideal solution to me. All tips are welcome :)
Js code:
var minutes = null, seconds = null, cnt, secs;
function settimer(frm) { if (minutes == null) { cnt = frm.timeinput.value - '1'; secs = '59';} };
function stop() {
clearInterval(minutes);
clearInterval(seconds);
minutes = null;
seconds = null;
document.getElementById("minutes").innerHTML = '00';
document.getElementById("seconds").innerHTML = '00';
}
function pause() {
clearInterval(minutes);
clearInterval(seconds);
}
function runtimer() {
event.preventDefault();
if (minutes == null) {
document.getElementById("minutes").innerHTML = cnt;};
minutes = setInterval(function () {
if (cnt == '0') { stop() } else { cnt -= 1; document.getElementById("minutes").innerHTML = cnt; };
}, 6000);
if (seconds == null) { document.getElementById("seconds").innerHTML = secs; };
seconds = setInterval(function () {
if (secs == '0') { secs = '59' } else { secs -= 1; document.getElementById("seconds").innerHTML = secs; };
}, 100);
}
You'll need to wrap them somehow, and recognise that you can't immediately get the timer's id.
function setIntervalWithOffset(fn, delay, offset) {
var o = {id: null, o_id: null};
o.o_id = window.setTimeout(function () {
o.id = window.setInterval(fn, delay);
}, offset);
return o;
}
function setTimeoutWithOffset(fn, delay, offset) {
var o = {id: null, o_id: null};
o.o_id = window.setTimeout(function () {
o.id = window.setTimeout(fn, delay);
}, offset);
return o;
}
To clear, use window.clearTimeout on obj.o_id and whichever type you set for obj.id.
You should also consider whether you'd be better off implementing a setTimeout loop rather than using setInterval so you don't have a chance of a cascade error
Sorry, I think that you are in a bad way. Why do you want to use two intervals to do the same thing? Intervals are asynchronous, you can not synchronize two intervals that runs independently.
You can achieve that with just one interval. To show seconds, you can just increment another variable each time that your counter reachs a threshold:
var counter = 0;
var seconds = 0;
var $interval = setInterval(function(){
counter++;
if (counter >= 6000) {
counter = counter - 6000;
seconds++;
}
, 10);
So, it will be more easy to stop/restart your interval.
You need to get the handle to the timer, in order to be able to reset it later, you can do like below:
timeoutHandle = setTimeout(function(){/*code*/}, 1000);
clearTimeout(timeoutHandle);
Take a look at this jsfiddle
Taken from : How do I stop a window.setInterval in javascript?

How to call a function every hour?

I am trying to update information from a weather service on my page. The info should be updated every hour on the hour. How exactly do I go about calling a function on the hour every hour?
I kind of had an idea but I'm not sure of how to actually refine it so it works...
What I had in mind was something like creating an if statement, such as: (pseudo code)
//get the mins of the current time
var mins = datetime.mins();
if(mins == "00"){
function();
}
You want to check out setInterval: https://developer.mozilla.org/en-US/docs/Web/API/Window.setInterval
It's a little hard to tell what you're trying to call with your code, but it would be something in the form of:
function callEveryHour() {
setInterval(yourFunction, 1000 * 60 * 60);
}
If you want it every hour, try something like:
var nextDate = new Date();
if (nextDate.getMinutes() === 0) { // You can check for seconds here too
callEveryHour()
} else {
nextDate.setHours(nextDate.getHours() + 1);
nextDate.setMinutes(0);
nextDate.setSeconds(0);// I wouldn't do milliseconds too ;)
var difference = nextDate - new Date();
setTimeout(callEveryHour, difference);
}
Now, this implementation checks the time once, sets the delay (or calls the function immediately), and then relies on setInterval to keep track after that. An alternative approach may be to poll the time every x many seconds/minutes, and fire it .getMinutes() == 0 instead (similar to the first part of the if-statement), which may sacrifice (marginal) performance for (marginal) accuracy. Depending on your exact needs, I would play around with both solutions.
Here is what should work (JSFiddle):
function tick() {
//get the mins of the current time
var mins = new Date().getMinutes();
if (mins == "00") {
alert('Do stuff');
}
console.log('Tick ' + mins);
}
setInterval(tick, 1000);
What you probably want is something like that:
var now = new Date();
var delay = 60 * 60 * 1000; // 1 hour in msec
var start = delay - (now.getMinutes() * 60 + now.getSeconds()) * 1000 + now.getMilliseconds();
setTimeout(function doSomething() {
// do the operation
// ... your code here...
// schedule the next tick
setTimeout(doSomething, delay);
}, start);
So basically the first time the user get the access, you need to know what is the delay in millisecond to the next "hour". So, if the user access to the page at 8:54 (with 56 seconds and 123 milliseconds), you have to schedule the first execution after around 3 minutes: after the first one is done, you can call it every "hour" (60 * 60 * 1000).
Repeat at specific minute past the hour
This counter is a little bit more versatile; it allows to perform a task repeatedly always at the same minute past the hour (e.g. 37 minutes past the hour), and this with up to millisecond precision.
The precision of this timer is derived from its recursion.
At every recursion, the millisecond time to the next minute gets recalculated. This prevents time lag over long periods.
The % sign refers to the modulo operator.
function minuteCount(minutesAfterHour) {
const now = new Date();
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
const milliseconds = now.getMilliseconds();
waitUntilNextMinute = setTimeout(minuteCount, 60000 - seconds * 1000 - milliseconds);
if(minutes % 60 === minutesAfterHour) {
doSomethingHourly();
}
}
minuteCount(37);
Finally, timers are best kept away from the main thread. They are best run from within a web worker, as explained here.
This works perfectly with unfocused tabs in desktop browsers.
However, dedicated web workers on Chrome for Android are put to sleep about 5 minutes after moving the main client to the background.
EDIT: Oops, I didn't see the " o' clock" things, so I edit my answer :
var last_execution = new Date().getTime();
function doSomething(force){
var current_time = new Date().getTime();
if (force || (current_time.getMinutes() == 0)
{
last_execution = current_time;
// something
// ...
}
setTimeout(doSomething(false), 1000);
}
// force the first time
doSomething(true);
// ... call your func now
let intervalId;
let timeoutId = setTimeout(() => {
// ... call your func on end of current hour
intervalId = setInterval(() => {
// ... call your func on end of each next hours
}, 3600000);
}, ((60 − moment().minutes()) × 60 × 1000) - (moment().second() * 1000));
Here is my pair of setIntervalWithDelay and clearIntervalWithDelay that one can use like this:
let descriptor = setIntervalWithDelay(callback, 60 * 60 * 1000, nextHourDelay)
And when you are done with it:
clearIntervalWithDelay(descriptor)
Here is my implementation of the functions:
const setIntervalWithDelay = (callback, interval, delay = 0) => {
let descriptor = {}
descriptor.timeoutId = setTimeout(() => {
if(!descriptor.timeoutId){
return
}
descriptor.timeoutId = null
callback()
descriptor.intervalId = setInterval(callback, interval)
}, delay)
return descriptor
}
export const clearIntervalWithDelay = (descriptor) => {
if(!isObject(descriptor) || (!descriptor.timeoutId && !descriptor.intervalId)){
console.warn("clearIntervalWithDelay: Incorrect descriptor. Please pass an object returned by setIntervalWithDelay. Skipping this call.")
return
}
if(descriptor.timeoutId){
clearTimeout(descriptor.timeoutId)
descriptor.timeoutId = null
console.log("clearIntervalWithDelay: stopped during delay.")
}
if(descriptor.intervalId){
clearInterval(descriptor.intervalId)
descriptor.intervalId = null
console.log("clearIntervalWithDelay: stopped during interval repeat.")
}
}
One example of using dayjs to get the delay for the next hour:
let nextHour = dayjs().second(0).millisecond(0).add(1, "hour")
let nextHourDelay = nextHour.diff(dayjs())

Categories