How to create a countdown that runs in the background using JavaScript? - javascript

I want to create a 3 hours countdown that runs in the background and repeats when it reaches 00:00:00. How can I do it using HTML and javascript? Thank you!

You can use Web Worker:
Run in background
No throttled ( settimeout-setinterval-on-inactive-tab )
// index.html
<div id="box">60</div>
<script>
let box = document.getElementById('box');
let worker = new Worker('countdown.js');
worker.postMessage(60);
worker.onmessage = function (event) {
box.innerHTML = event.data;
}
</script>
// countdown.js
onmessage = function (e) {
let num = e.data;
let count = setInterval(function () {
postMessage(--num);
if (num <= 0) {
clearInterval(count);
close();
}
}, 1000);
}

For background countdown. I think the big issue that you need to face is when you are leave the page or open a new tabs. right?
Do you want to make the countdown work even the tab is not active?
maybe requestAnimationFrame is helpful for you.
function showTime() {
remainingTime = getRemainingTime(endTime);
var seconds = pad((remainingTime / 1000));
console.log('remain time is: ', seconds + " sec")
if (remainingTime >= 1000) {
window.requestAnimationFrame(showTime);
} else {
console.log('Time up!!!')
}
}
function getRemainingTime(deadline) {
var currentTime = new Date().getTime();
return deadline - currentTime;
}
function pad(value) {
var sl = (""+Math.floor(value)).length;
if(sl > 2){
return ('0' + Math.floor(value)).slice(-sl);
}
return ('0' + Math.floor(value)).slice(-2);
}
endTime = new Date().getTime() + 1000*60;
window.requestAnimationFrame(showTime);
Demo here: https://codepen.io/quanhv/pen/oNZWxvB

Related

Calculating time after pressing button (javascript)

I'm trying to make a reaction test website just for fun, but I don't know how to calculate the time taken between button presses.
I found this
var startTime;
function startButton() {
startTime = Date.now();
}
function stopButton() {
if (startTime) {
var endTime = Date.now();
var difference = endTime - startTime;
alert('Reaction time: ' + difference + ' ms');
startTime = null;
} else {
alert('Click the Start button first');
}
}
but it only works for 2 buttons (I only want one). So I tried making a function, something like
function calculateTime(){
startButton();
stopButton();
}
but of course, it doesn't work since it will stop the timer immediately. Any way to get around it?
Use a single function that checks whether startTime has been set or not. If it hasn't been set, it sets it; otherwise, it reports the time difference.
let startTime = null;
const button = document.querySelector("#timer");
button.addEventListener("click", startStop);
const output = document.querySelector("#output");
function startStop() {
if (startTime) {
var endTime = Date.now();
var difference = endTime - startTime;
output.innerText = 'Reaction time: ' + difference + ' ms';
startTime = null;
button.innerText = "Start Timer";
} else {
startTime = Date.now();
button.innerText = "Stop Timer";
output.innerText = "";
}
}
<button id="timer">Start Timer</button><br>
<div id="output"></div>
You were close. You need to declare the start time outside of the function so that it persists between function calls and then use the else section of the if statement to set it.
let startTime;
document.querySelector("button").addEventListener("click", startStop);
function startStop() {
if (startTime) {
console.log("Clock stopped");
var endTime = Date.now();
var difference = endTime - startTime;
alert('Reaction time: ' + difference + ' ms');
startTime = null;
} else {
startTime = Date.now();
console.log("Clock started");
}
}
<button>Start/Stop</button>
You can use performace.now() or console.time to calucalte time after press button.
var performance = window.performance;
var t0 = performance.now();
------your function--------
var t1 = performance.now();
console.log("This function took " + (t1 - t0) + " milliseconds.")
function a() {
console.time("buttontimer");
... your function ...
var dur = console.timeEnd("buttontimer"); // NOTE: dur only works in FF
}

Why does my Web Worker stops decreasing a timer after couple of seconds?

I've came across with an interesting event.
I'm trying to build a pomodoro timer that runs in the background with an alarm that fires when the timer finishes and starts.
I coded a WebWorker Script that runs that same timer.
worker.js
self.addEventListener("message", (e) => {
if (e.data.task === 'run the timer') {
currentTimeLeftInSession = e.data.defaultWorkTime;
countdown = setInterval(() => {
currentTimeLeftInSession--;
currentTimeLeftInSessionBackwards++;
if(currentTimeLeftInSession < 0) {
return;
}
let timeLeft = getTimeLeft(currentTimeLeftInSession);
let data = {
'timeLeft': timeLeft,
}
self.postMessage(data);
}, 1000);
}
function getTimeLeft(seconds) {
let minutes = Math.floor(seconds / 60);
let remainderSeconds = Math.floor(seconds % 60);
let timeLeft = `${minutes}:${remainderSeconds}`;
if (remainderSeconds < 10) {
timeLeft = `${minutes}:0${remainderSeconds}`;
if (minutes < 10) {
timeLeft = `0${minutes}:0${remainderSeconds}`;
}
}
return timeLeft;
}
})
And added an event listener to the pomodoro script that updates the timer display
pomodoro.js
let worker = new Worker('/lib/js/worker.js')
worker.addEventListener('message', (e) => {
progressBar.text.innerText = e.data.timeLeft;
console.log(e.data.timeLeft)
if(e.data.timeLeft == '00:00') {
playAudio(audioNumber);
}
});
startButton.addEventListener('click', () => {
defaultWorkTime = 200
let data = {
'task': 'run the timer',
'defaultWorkTime': defaultWorkTime,
'defaultBreakTime': defaultBreakTime,
}
worker.postMessage(data);
});
The interesting thing here:
If i remove the console.log the timer stops getting updated. If i set it all goes with the plan.
Why does this happen???
Is there a way that the timer doesn't stop after couple of seconds if it's running on background?

socket.on doesn't fire the first time

Why doesn't this fire the first time? I'm not sure I understand this, please help! When I run pause() the second time, then it fires. Not sure what i'm doing wrong here.
this.pause = function (stopwatch){
this.stopwatch = stopwatch;
socket.emit('pauseTime'); //server does fire "paustime"
// this doesn't fire
socket.on('pauseTimeClock', function(data){
stopWatchClock.setPausedTime(data.time);
$('.pauseTime').html(data.time.replace(/(\d)/g, '<span>$1</span>'))
console.log(stopWatchClock.pausedTime);
});
this.stopwatch.changeState(this.stopwatch.getPauseState());
}
server code
socket.on('pauseTime', function () {
//stop broadcasting countDown time
clearInterval(timeinterval);
var pausedTime = moment();
function pauseTimeClock() {
var timeDiffHour = moment().hour() - pausedTime.hour();
var timeDiffMinute = moment().minute() - pausedTime.minute();
var timeDiffSec = moment().second();
var displayTime = timeDiffHour + ":" + timeDiffMinute + ":" + timeDiffSec;
socket.broadcast.emit("pauseTimeClock", { time: moment(displayTime, 'hhmm').format('HH:mm') });
console.log(timeDiffHour);
console.log(timeDiffMinute);
}
setInterval(pauseTimeClock, 1000);
})

Stopping timer not working:

I have THIS timer in my project.
When it runs out, it shows a Time Up screen, which works fine.
But when the player is Game Over, i show the Game Over screen, but the timer keeps running and when it hits 00:00 then it switches to the Time Up screen.
How can i make this timer stop counting down and set to 00:00 again?
I tried adding a function like this:
CountDownTimer.prototype.stop = function() {
diff = 0;
this.running = false;
};
I also tried to change the innerHTML but its obvious that its just changing the numbers without stopping the timer and after a second it will show the count down again... I don't know what to call.
//Crazy Timer function start
function CountDownTimer(duration, granularity) {
this.duration = duration;
this.granularity = granularity || 1000;
this.tickFtns = [];
this.running = false;
}
CountDownTimer.prototype.start = function() {
if (this.running) {
return;
}
this.running = true;
var start = Date.now(),
that = this,
diff, obj;
(function timer() {
diff = that.duration - (((Date.now() - start) / 1000) | 0);
if (diff > 0) {
setTimeout(timer, that.granularity);
} else {
diff = 0;
that.running = false;
}
obj = CountDownTimer.parse(diff);
that.tickFtns.forEach(function(ftn) {
ftn.call(this, obj.minutes, obj.seconds);
}, that);
}());
};
CountDownTimer.prototype.onTick = function(ftn) {
if (typeof ftn === 'function') {
this.tickFtns.push(ftn);
}
return this;
};
CountDownTimer.prototype.expired = function() {
return !this.running;
};
CountDownTimer.parse = function(seconds) {
return {
'minutes': (seconds / 60) | 0,
'seconds': (seconds % 60) | 0
};
};
window.onload = function () {
var display = document.querySelector('#countDown'),
timer = new CountDownTimer(timerValue),
timeObj = CountDownTimer.parse(timerValue);
format(timeObj.minutes, timeObj.seconds);
timer.onTick(format).onTick(checkTime);
document.querySelector('#startBtn').addEventListener('click', function () {
timer.start();
});
function format(minutes, seconds) {
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ':' + seconds;
}
function checkTime(){
if(this.expired()) {
timeUp();
document.querySelector('#startBtn').addEventListener('click', function () {
timer.start();
});
}
}
};
Instead of recursively calling setTimeout, try setInterval instead. You could then store a reference to the timer:
this.timer = setInterval(functionToRunAtInterval, this.granularity);
and kill it when the game finishes::
clearInterval(this.timer)
(see MDN's docs for more info on setInterval)
It's been a while and I'm not sure if you've figured it out but check out the fiddle below:
https://jsfiddle.net/f8rh3u85/1/
// until running is set to false the timer will keep running
if (that.running) {
if (diff > 0) {
setTimeout(timer, that.granularity);
} else {
diff = 0;
that.running = false;
}
obj = CountDownTimer.parse(diff);
that.tickFtns.forEach(function(ftn) {
ftn.call(this, obj.minutes, obj.seconds);
}, that);
}
I've added a button that causes running to be set to false which stops the timer.
Button:
<button id="stop">Game Over</button>
Code:
$( "#stop" ).click(function() {
timer.running = false;
});
So that should hopefully get you to where you need to be.
Similar to Tom Jenkins' answer, you need to cancel the next tick by avoiding the diff > 0 branch of your if statement. You could keep your code as it stands and use your suggested stop method, however, you'd need to change your logic around handling ticks to check that both running === true and a new param gameOver === false.
Ultimately, I think your problem is that no matter whether the timer is running or not, you'll always execute this code on a tick:
obj = CountDownTimer.parse(diff);
that.tickFtns.forEach(function(ftn) {
ftn.call(this, obj.minutes, obj.seconds);
}, that);
If you have a game over state, you probably don't want to call the provided callbacks, so add some conditional check in there.

How to pause and resume a javascript timer [duplicate]

This question already has an answer here:
how to pause timer or freeze it and resume -> javascript
(1 answer)
Closed 9 years ago.
I have this timer which works fine, but i need to be able to pause and resume it after that. i would appreciate it if someone could help me.
<html>
<head>
<script>
function startTimer(m,s)
{
document.getElementById('timer').innerHTML= m+":"+s;
if (s==0)
{
if (m == 0)
{
return;
}
else if (m != 0)
{
m = m-1;
s = 60;
}
}
s = s-1;
t=setTimeout(function(){startTimer(m,s)},1000);
}
</script>
</head>
<body>
<button onClick = "startTimer(5,0)">Start</button>
<p id = "timer">00:00</p>
</body>
</html>
I simply can't stand to see setTimeout(...,1000) and expecting it to be exactly 1,000 milliseconds. Newsflash: it's not. In fact, depending on your system it could be anywhere between 992 and 1008, and that difference will add up.
I'm going to show you a pausable timer with delta timing to ensure accuracy. The only way for this to not be accurate is if you change your computer's clock in the middle of it.
function startTimer(seconds, container, oncomplete) {
var startTime, timer, obj, ms = seconds*1000,
display = document.getElementById(container);
obj = {};
obj.resume = function() {
startTime = new Date().getTime();
timer = setInterval(obj.step,250); // adjust this number to affect granularity
// lower numbers are more accurate, but more CPU-expensive
};
obj.pause = function() {
ms = obj.step();
clearInterval(timer);
};
obj.step = function() {
var now = Math.max(0,ms-(new Date().getTime()-startTime)),
m = Math.floor(now/60000), s = Math.floor(now/1000)%60;
s = (s < 10 ? "0" : "")+s;
display.innerHTML = m+":"+s;
if( now == 0) {
clearInterval(timer);
obj.resume = function() {};
if( oncomplete) oncomplete();
}
return now;
};
obj.resume();
return obj;
}
And use this to start/pause/resume:
// start:
var timer = startTimer(5*60, "timer", function() {alert("Done!");});
// pause:
timer.pause();
// resume:
timer.resume();
<p id="timer">00:00</p>
<button id="start">Start</button>
<button id="pause">Pause</button>
<button id="resume">Resume</button>
var timer = document.getElementById("timer");
var start = document.getElementById("start");
var pause = document.getElementById("pause");
var resume = document.getElementById("resume");
var id;
var value = "00:00";
function startTimer(m, s) {
timer.textContent = m + ":" + s;
if (s == 0) {
if (m == 0) {
return;
} else if (m != 0) {
m = m - 1;
s = 60;
}
}
s = s - 1;
id = setTimeout(function () {
startTimer(m, s)
}, 1000);
}
function pauseTimer() {
value = timer.textContent;
clearTimeout(id);
}
function resumeTimer() {
var t = value.split(":");
startTimer(parseInt(t[0], 10), parseInt(t[1], 10));
}
start.addEventListener("click", function () {
startTimer(5, 0);
}, false);
pause.addEventListener("click", pauseTimer, false);
resume.addEventListener("click", resumeTimer, false);
on jsfiddle
There are a whole load of improvements that could be made but I'm sticking with the code that the OP posted for the OP's comprehension.
Here is an extended version to give you further ideas on jsfiddle

Categories

Resources