Timer shows wrong results - javascript

var seconds_lapsed = 0;
function tick() {
seconds_lapsed++;
}
function countup() {
setTimeout(function () {
if (stopped) return; // stop the loop
if (!is_paused()) {
tick();
show_time_left();
}
countup(); // <--- this is the "loop"
}, 1000);
}
This is the core of my timer. Of course I have some view to represent the result. But ticking is done here.
The problem
It shows wrong time. Have a look at this:
The timer was set for 3 hours. Twelve minutes lapsed. And the discrepancy is almost 1.5 minutes.
In the other window the timer by Google is working. This one:
So, I just compared my timer with that of google. I started them almost at once. The difference should be no more than a couple of seconds (to switch the window and press the button).
What is the reason for this, and how can I correct it?

setTimeout with an interval of 1000 does NOT run exactly after every 1 seconds.
It schedules to run after 1 second, but can be delayed with by actions running at that time.
A better way of solving this is by calculating via date difference.
I took your sample (added the missing vars/funcs) and changed the tick() function to use date diffs.
var seconds_lapsed = 0;
var startDateTime = new Date();
var stopped = false;
var is_paused = function() { return false; }
function tick() {
datediffInms = new Date() - startDateTime;
seconds_lapsed = Math.round(datediffInms / 1000);
}
function countup() {
setTimeout(function () {
if (stopped) return; // stop the loop
if (!is_paused()) {
tick();
//show_time_left();
console.log(seconds_lapsed)
}
countup(); // <--- this is the "loop"
}, 1000);
}
countup();

Related

javascript - how to control setinterval internal

In my application development, I am using
setInterval(function() {
// some code
// runs here
}, 60000);
I want to execute some code on 1 minute interval and my code may take 2-3 minutes in some cases.
<execute code> - <wait 1 minute> - <execute code> - <wait 1 minute> ......so on
I tried with setInterval function but noticed that setInterval does not wait for inner code to complete. Please suggest how can i achieve this in javascript.
Thanks
A better way may be to recursively call your job function with setTimeout:
setTimeout(function jobThatRunEveryMinute() {
// run code here that may take more than one minute
someExpensiveCodeToRun()
// start another job after someExpensiveCode completes
setTimeout(jobThatRunEveryMinute, 60000);
}, 60000);
Something like this might work for you, but why do you have a function that takes over 1 min to return something?
let callCompleted = true;
setInterval(function() {
if (callCompleted) {
callCompleted = false;
// pass a call back function to update the callCompleted to true
myLongRunningFunction(function() { callCompleted = true } );
// or if `myLongRunningFunction` returns a promise
myLongRunningFunction.then(() => { callCompleted = true } );
}
}, 60000);
// adjust wait time to your liking
const waitTime = 10000
let time = 0
// so you can stop it
const totalTime = 6
function excuteCode() {
time++;
console.log(time); // <=== replace with your inner code
if (time < totalTime) {
setTimeout(() => {
excuteCode()
}, waitTime)
}
}
excuteCode();

Javascript - Pausing an IIFE output that has setTimeout and displays min/sec - Pomodoro Clock

I have two functions that display minutes and seconds. Inside the functions I'm using an IIFE with a setTimeout to calculate the time. After getting this, having a hard time figuring out how I could pause the display if pause button is clicked.
The timer works fine and displays correctly.
I realize this is probably not a good way to do it, but I spent so much time (trying to learn how to use IIFE) that I don't want to give up. If I have to, then I will scratch it.
Update - This timer will be getting input from the user. It might be 25 minutes. I want it to start counting down from there until it reaches 0, and the user able to pause at anytime.
let convertToSeconds = document.getElementById('timeValue').value * 60;
let seconds = 60;
function secondsCounter(time) {
// let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
})(i);
}
}
function counter() {
for (let i = convertToSeconds; i > 0; i--) {
(function(minutes) {
setTimeout(function() {
let remaining = Math.floor((convertToSeconds - minutes) / 60);
document.getElementById('displayMinutes').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
setTimeout(function() {
secondsCounter(seconds);
}, i * 60000);
})(i);
}
secondsCounter(seconds);
}
I've tried a couple of things.
Using a flag and if statement around document.getElementById('displaySeconds').innerHTML = remaining; so if my pause button is clicked, the flag changes, and another setTimeout (10 minutes) is triggered. Doesn't stop the countdown on the DOM, it keeps going. I just wanted to see some reaction, but nothing happened. Something like:
function secondsCounter(time) {
let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
if (flag === 'yes') {
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
} else {
setTimeout(function() {
console.log(remaining);
}, 10000);
}
}, i * 1000);
})(i);
}
}
Using a setInterval and clearInterval that didn't do anything.
Is this possible? Not sure where else to look. Thank you
You can't stop/pause a setTimeout or clearTimeout without making a reference to the timer, storing it and then calling clearTimeout(timer) or clearInterval(timer).
So, instead of: setTimeout(someFunciton)
You need: timer = setTimeout(someFunciton)
And, the timer variable needs to be declared in a scope that is accessible to all functions that will use it.
See setTimeout() for details.
Without a reference to the timer, you will not be able to stop it and that's caused you to go on a wild goose chase for other ways to do it, which is overthinking what you actually need.
In the end, I think you should just have one function that does all the counting down so that you only have one timer to worry about.
Lastly, you can use the JavaScript Date object and its get / set Hours, Minutes and Seconds methods to take care of the reverse counting for you.
(function() {
// Ask user for a time to start counting down from.
var countdown = prompt("How much time do you want to put on the clock? (hh:mm:ss)");
// Take that string and split it into the HH, MM and SS stored in an array
var countdownArray = countdown.split(":")
// Extract the individual pieces of the array and convert to numbers:
var hh = parseInt(countdownArray[0],10);
var mm = parseInt(countdownArray[1],10);
var ss = parseInt(countdownArray[2],10);
// Make a new date and set it to the countdown value
var countdownTime = new Date();
countdownTime.setHours(hh, mm, ss);
// DOM object variables
var clock = null, btnStart = null, btnStop = null;
// Make a reference to the timer that will represent the running clock function
var timer = null;
window.addEventListener("DOMContentLoaded", function () {
// Make a cache variable to the DOM element we'll want to use more than once:
clock = document.getElementById("clock");
btnStart = document.getElementById("btnStart");
btnStop = document.getElementById("btnStop");
// Wire up the buttons
btnStart.addEventListener("click", startClock);
btnStop.addEventListener("click", stopClock);
// Start the clock
startClock();
});
function startClock() {
// Make sure to stop any previously running timers so that only
// one will ever be running
clearTimeout(timer);
// Get the current time and display
console.log(countdownTime.getSeconds());
countdownTime.setSeconds(countdownTime.getSeconds() - 1);
clock.innerHTML = countdownTime.toLocaleTimeString().replace(" AM", "");
// Have this function call itself, recursively every 900ms
timer = setTimeout(startClock, 900);
}
function stopClock() {
// Have this function call itself, recursively every 900ms
clearTimeout(timer);
}
}());
<div id="clock"></div>
<button id="btnStart">Start Clock</button>
<button id="btnStop">Stop Clock</button>

js setInterval - increase speed gradually

How can I make setInterval to increase speed gradually, like start from 1000 ms and than go down until 40 ms gradually in few seconds by 1 ms at a time.
Any thoughts?
This is my code:
setTimeout(function() {bonustimer = setInterval(function() { handleTimer2(rushcount); }, 40);}, 1000);
handleTimer2 = function() {
if(rushcount === -1) {
clearInterval(bonustimer);
} else {
$('.digit-wrapper').html(rushcount);
rushcount--;
}}
Set interval probably wouldn't be what you want here, as you just end up killing it and redoing it on every iteration. Much easier to use setTimeout, possibly something like this:
(function () {
var interval = 1001;
timer = function() {
--interval;
//do your thing here
if (interval >= 40) {
setTimeout(timer, interval);
}
};
timer();
})();
Also note that if you only decrease the interval by one ms at a time, from 1000 down to 40, it takes quite a while to go through all those iterations. You can always replace --interval by some other formula, like interval = interval*0.9; (to reduce by 10% each iteration) or whatever formula you want.
I guess the code by #OldGeeksGuide just stops when the interval reaches 40. Needs a little improvement ;)
(function () {
var interval = 1000;
timer = function() {
interval--;
//do your thing here
interval = interval < 40 ? 40 : interval;
setTimeout(timer, interval);
};
timer();
})();
Then you could maybe need to stop this loop by wrapping the setTimeout with some if condition ;)

Accurately run a function when the minute changes?

How could I accurately run a function when the minute changes? Using a setInterval could work if I trigger it right when the minute changes. But I'm worried setInterval could get disrupted by the event-loop in a long-running process and not stay in sync with the clock.
How can I run a function accurately when the minute changes?
First off, you should use setInterval for repeating timers, since it (tries to) guarantee periodic execution, i.e. any potential delays will not stack up as they will with repeated setTimeout calls. This will execute your function every minute:
var ONE_MINUTE = 60 * 1000;
function showTime() {
console.log(new Date());
}
setInterval(showTime, ONE_MINUTE);
Now, what we need to do is to start this at the exact right time:
function repeatEvery(func, interval) {
// Check current time and calculate the delay until next interval
var now = new Date(),
delay = interval - now % interval;
function start() {
// Execute function now...
func();
// ... and every interval
setInterval(func, interval);
}
// Delay execution until it's an even interval
setTimeout(start, delay);
}
repeatEvery(showTime, ONE_MINUTE);
This may be an idea. The maximum deviation should be 1 second. If you want it to be more precise, lower the milliseconds of setTimeout1.
setTimeout(checkMinutes,1000);
function checkMinutes(){
var now = new Date().getMinutes();
if (now > checkMinutes.prevTime){
// do something
console.log('nextminute arrived');
}
checkMinutes.prevTime = now;
setTimeout(checkChange,1000);
}
1 But, see also this question, about accuracy of timeouts in javascript
You can try to be as accurate as you can, setting a timeout each X milliseconds and check if the minute has passed and how much time has passed since the last invocation of the function, but that's about it.
You cannot be 100% sure that your function will trigger exactly after 1 minute, because there might be something blocking the event-loop then.
If it's something vital, I suggest using a cronjob or a separate Node.js process specifically for that (so you can make sure the event loop isn't blocked).
Resources:
http://www.sitepoint.com/creating-accurate-timers-in-javascript/
I've put up a possible solution for you:
/* Usage:
*
* coolerInterval( func, interval, triggerOnceEvery);
*
* - func : the function to trigger
* - interval : interval that will adjust itself overtime checking the clock time
* - triggerOnceEvery : trigger your function once after X adjustments (default to 1)
*/
var coolerInterval = function(func, interval, triggerOnceEvery) {
var startTime = new Date().getTime(),
nextTick = startTime,
count = 0;
triggerOnceEvery = triggerOnceEvery || 1;
var internalInterval = function() {
nextTick += interval;
count++;
if(count == triggerOnceEvery) {
func();
count = 0;
}
setTimeout(internalInterval, nextTick - new Date().getTime());
};
internalInterval();
};
The following is a sample usage that prints the timestamp once every minute, but the time drift is adjusted every second
coolerInterval(function() {
console.log( new Date().getTime() );
}, 1000, 60);
It's not perfect, but should be reliable enough.
Consider that the user could switch the tab on the browser, or your code could have some other blocking tasks running on the page, so a browser solution will never be perfect, it's up to you (and your requirements) to decide if it's reliable enough or not.
Tested in browser and node.js
sleeps until 2 seconds before minute change then waits for change
you can remove logging as it gets pretty cluttered in log otherwise
function onMinute(cb,init) {
if (typeof cb === 'function') {
var start_time=new Date(),timeslice = start_time.toString(),timeslices = timeslice.split(":"),start_minute=timeslices[1],last_minute=start_minute;
var seconds = 60 - Number(timeslices[2].substr(0,2));
var timer_id;
var spin = function (){
console.log("awake:ready..set..");
var spin_id = setInterval (function () {
var time=new Date(),timeslice = time.toString(),timeslices = timeslice.split(":"),minute=timeslices[1];
if (last_minute!==minute) {
console.log("go!");
clearInterval(spin_id);
last_minute=minute;
cb(timeslice.split(" ")[4],Number(minute),time,timeslice);
console.log("snoozing..");
setTimeout(spin,58000);
}
},100);
};
setTimeout(spin,(seconds-2)*1000);
if (init) {
cb(timeslice.split(" ")[4],Number(start_minute),start_time,timeslice,seconds);
}
}
}
onMinute(function (timestr,minute,time,timetext,seconds) {
if (seconds!==undefined) {
console.log("started waiting for minute changes at",timestr,seconds,"seconds till first epoch");
} else {
console.log("it's",timestr,"and all is well");
}
},true);
My first thought would be to use the Date object to get the current time. This would allow you to set your set interval on the minute with some simple math. Then since your worried about it getting off, every 5-10 min or whatever you think is appropriate, you could recheck the time using a new date object and readjust your set interval accordingly.
This is just my first thought though in the morning I can put up some code(its like 2am here).
This is a fairly straightforward solution ... the interval for the timeout is adjusted each time it's called so it doesn't drift, with a little 50ms safety in case it fires early.
function onTheMinute(callback) {
const remaining = 60000 - (Date.now() % 60000);
setTimeout(() => {
callback.call(null);
onTheMinute(callback);
}, remaining + (remaining < 50 ? 60000 : 0));
}
Here's yet another solution based on #Linus' post and #Brad's comment. The only difference is it's not working by calling the parent function recursively, but instead is just a combination of setInterval() and setTimeout():
function callEveryInterval(callback, callInterval){
// Initiate the callback function to be called every
// *callInterval* milliseconds.
setInterval(interval => {
// We don't know when exactly the program is going to starts
// running, initialize the setInterval() function and, from
// thereon, keep calling the callback function. So there's almost
// surely going to be an offset between the host's system
// clock's minute change and the setInterval()'s ticks.
// The *delay* variable defines the necessary delay for the
// actual callback via setTimeout().
let delay = interval - new Date()%interval
setTimeout(() => callback(), delay)
}, callInterval, callInterval)
}
Small, maybe interesting fact: the callback function only begins executing on the minute change after next.
The solution proposed by #Linus with setInterval is in general correct, but it will work only as long as between two minutes there are exactly 60 seconds. This seemingly obvious assumption breaks down in the presence of a leap second or, probably more frequently, if the code runs on a laptop that get suspended for a number of seconds.
If you need to handle such cases it is best to manually call setTimeout adjusting every time the interval. Something like the following should do the job:
function repeatEvery( func, interval ) {
function repeater() {
repeatEvery( func, interval);
func();
}
var now = new Date();
var delay = interval - now % interval;
setTimeout(repeater, delay);
}

Calling a function every 60 seconds

Using setTimeout() it is possible to launch a function at a specified time:
setTimeout(function, 60000);
But what if I would like to launch the function multiple times? Every time a time interval passes, I would like to execute the function (every 60 seconds, let's say).
If you don't care if the code within the timer may take longer than your interval, use setInterval():
setInterval(function, delay)
That fires the function passed in as first parameter over and over.
A better approach is, to use setTimeout along with a self-executing anonymous function:
(function(){
// do some stuff
setTimeout(arguments.callee, 60000);
})();
that guarantees, that the next call is not made before your code was executed. I used arguments.callee in this example as function reference. It's a better way to give the function a name and call that within setTimeout because arguments.callee is deprecated in ecmascript 5.
use the
setInterval(function, 60000);
EDIT : (In case if you want to stop the clock after it is started)
Script section
<script>
var int=self.setInterval(function, 60000);
</script>
and HTML Code
<!-- Stop Button -->
Stop
A better use of jAndy's answer to implement a polling function that polls every interval seconds, and ends after timeout seconds.
function pollFunc(fn, timeout, interval) {
var startTime = (new Date()).getTime();
interval = interval || 1000;
(function p() {
fn();
if (((new Date).getTime() - startTime ) <= timeout) {
setTimeout(p, interval);
}
})();
}
pollFunc(sendHeartBeat, 60000, 1000);
UPDATE
As per the comment, updating it for the ability of the passed function to stop the polling:
function pollFunc(fn, timeout, interval) {
var startTime = (new Date()).getTime();
interval = interval || 1000,
canPoll = true;
(function p() {
canPoll = ((new Date).getTime() - startTime ) <= timeout;
if (!fn() && canPoll) { // ensures the function exucutes
setTimeout(p, interval);
}
})();
}
pollFunc(sendHeartBeat, 60000, 1000);
function sendHeartBeat(params) {
...
...
if (receivedData) {
// no need to execute further
return true; // or false, change the IIFE inside condition accordingly.
}
}
In jQuery you can do like this.
function random_no(){
var ran=Math.random();
jQuery('#random_no_container').html(ran);
}
window.setInterval(function(){
/// call your function here
random_no();
}, 6000); // Change Interval here to test. For eg: 5000 for 5 sec
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="random_no_container">
Hello. Here you can see random numbers after every 6 sec
</div>
setInterval(fn,time)
is the method you're after.
You can simply call setTimeout at the end of the function. This will add it again to the event queue. You can use any kind of logic to vary the delay values. For example,
function multiStep() {
// do some work here
blah_blah_whatever();
var newtime = 60000;
if (!requestStop) {
setTimeout(multiStep, newtime);
}
}
Use window.setInterval(func, time).
A good example where to subscribe a setInterval(), and use a clearInterval() to stop the forever loop:
function myTimer() {
}
var timer = setInterval(myTimer, 5000);
call this line to stop the loop:
clearInterval(timer);
Call a Javascript function every 2 second continuously for 10 second.
var intervalPromise;
$scope.startTimer = function(fn, delay, timeoutTime) {
intervalPromise = $interval(function() {
fn();
var currentTime = new Date().getTime() - $scope.startTime;
if (currentTime > timeoutTime){
$interval.cancel(intervalPromise);
}
}, delay);
};
$scope.startTimer(hello, 2000, 10000);
hello(){
console.log("hello");
}
function random(number) {
return Math.floor(Math.random() * (number+1));
}
setInterval(() => {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';//rgb value (0-255,0-255,0-255)
document.body.style.backgroundColor = rndCol;
}, 1000);
<script src="test.js"></script>
it changes background color in every 1 second (written as 1000 in JS)
// example:
// checkEach(1000, () => {
// if(!canIDoWorkNow()) {
// return true // try again after 1 second
// }
//
// doWork()
// })
export function checkEach(milliseconds, fn) {
const timer = setInterval(
() => {
try {
const retry = fn()
if (retry !== true) {
clearInterval(timer)
}
} catch (e) {
clearInterval(timer)
throw e
}
},
milliseconds
)
}
here we console natural number 0 to ......n (next number print in console every 60 sec.) , using setInterval()
var count = 0;
function abc(){
count ++;
console.log(count);
}
setInterval(abc,60*1000);
I see that it wasn't mentioned here if you need to pass a parameter to your function on repeat setTimeout(myFunc(myVal), 60000); will cause an error of calling function before the previous call is completed.
Therefore, you can pass the parameter like
setTimeout(function () {
myFunc(myVal);
}, 60000)
For more detailed information you can see the JavaScript garden.
Hope it helps somebody.
I favour calling a function that contains a loop function that calls a setTimeout on itself at regular intervals.
function timer(interval = 1000) {
function loop(count = 1) {
console.log(count);
setTimeout(loop, interval, ++count);
}
loop();
}
timer();
There are 2 ways to call-
setInterval(function (){ functionName();}, 60000);
setInterval(functionName, 60000);
above function will call on every 60 seconds.

Categories

Resources