In an agenda/calendar app I'm working on, I display a line to indicate the current time. I want to update the position of this line every minute.
If I start a setInterval function when the calendar component did mount or will mount, there is a change that it starts at the 59th second (or just not the 1st second) and the time will always be different from the time that the device is showing (computer, smartphone, ...).
But I would like that both times are matching. So I was wondering if it is possible to start the interval when a new minute starts of if there is another way to get a time update.
EDIT: Current code
componentDidMount() {
setInterval(() => {
this.setState({ currentTime: new Date() })
}, 60 * 1000);
}
You can get fairly close, by calculating the number of seconds until the next minute, and performing a timeout on the difference.
(function showTime(){
console.log('update time');
var time = document.getElementById('time');
var now = new Date();
time.innerHTML = `${now.getHours()}:${now.getMinutes()}`;
setTimeout(showTime, (60 - now.getSeconds()) * 1000);
})();
<div id="time"></div>
Use SetTimeout to call a function that repairs any deviation for each iteration and relaunches with a new call to setTimout.
function repairAndRelaunch (cnt) {
// capture current secs
var secs = (new Date()).getSeconds();
// relaunch with corrected seconds - limit iterations for testing
if (5 > cnt++) setTimeout('repairAndRelaunch(' + cnt + ')', (60-secs)*1000);
// log to observe discrepencies
console.log('for cnt = ' + cnt + ', secs = ' + secs);
};
// test control flow
window.onload = function() {repairAndRelaunch(0);};
Related
I have an api request that is called multiple times in a given amount of time. More specifically this request is for refreshing the user token, so it's called on every request, which adds up pretty quickly. I would like to create a function that tells the function not to run for a given amount of seconds. I have tried using lodash debounce but I can't get it to work.
let debounceRefresh;
debounceRefresh = debounce(() => {
api.request(){
});
}, 1000);
debounceRefresh();
Am I executing this wrong? Is it possible to do?
Yes, you definitely need throttle for the job.
// in this example we invoke a fn for a period of 10 sec, invoking it 2 times a second, but we can perceive that the original function is only invoked at most once per 2 seconds according to the parameter below:
var TOTAL_TIME_TO_RUN = 10000; // 10 sec
var THROTTLE_INTERVAL = 2000; // <= adjust this number to see throttling in action
var INVOCATION_INTERVAL = 500; // 0.5 sec
// regular fn
var punchClock = function punchClock() {
console.log(new Date().toISOString() + ' - call api');
};
// wrap it and supply interval representing minimum delay between invocations
var throttledPunchClock = _.throttle(punchClock, THROTTLE_INTERVAL);
// set up looping
var intervalId = setInterval(function() {
console.log("attempting call api");
throttledPunchClock()
}, INVOCATION_INTERVAL);
// run the demo
setTimeout(() => clearInterval(intervalId), 10000)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
<pre>
var TOTAL_TIME_TO_RUN = 10000; // 10 sec
var THROTTLE_INTERVAL = 2000; // < = adjust this number to see throttling in action
var INVOCATION_INTERVAL = 500; // 0.5 sec
</pre>
Snippet from github
Have you tried with a timeout?
const myTimeout = setTimeout(debounceRefresh, 1000);
If the function is called again, you can clear the timeout and reset it
clearTimeout(myTimeout);
Why don't you use a different listener? Perhaps when data is received?
I want to make the seconds synchronize with the real time (new Date()) seconds, so that it would work if the page was loaded mid second.
setInterval(() => {
console.log("hey im not synchronized");
}, 1000);
Is that possible?
Is that possible?
Yep, like this:
setTimeout(() => {
setInterval(() => console.log("hey im synchronized"), 1000)
}, 1000 - new Date().getMilliseconds());
For this particular purpose, what you want is a self-synchronizing timing loop. The basic idea is not to use setInterval(), but rather to calculate each time how many milliseconds later you want the loop to fire next time, and use setTimeout() to wait until then.
Here's a basic example:
function oncePerSecond(callback) {
var timerFunc = function () {
// get the current time rounded down to a whole second (with a 10% margin)
var now = 1000 * Math.floor(Date.now() / 1000 + 0.1);
// run the callback
callback(now);
// wait for the next whole second
setTimeout(timerFunc, now + 1000 - Date.now());
};
timerFunc();
}
// create a demo timer
oncePerSecond(function (now) {
document.getElementById('local').textContent = new Date(now).toString();
});
// add an artificial 0.5 second delay for the second timer
setTimeout(function () {
oncePerSecond(function (now) {
document.getElementById('utc').textContent = new Date(now).toUTCString();
});
}, 500);
<p>The local time is now: <span id="local">...</span></p>
<p>The UTC time is now: <span id="utc">...</span></p>
Note how, even though the two timers in the snippet above start half a second apart, they synchronize immediately after the first update.
The reason for the funny-looking + 0.1 fudge factor in Math.floor(Date.now() / 1000 + 0.1) is because there's no guarantee that the timer won't sometimes fire early, just a few milliseconds before the clock ticks over. The 0.1 second offset ensures that we'll round the current time forward in such cases, but that we'll still normally round the time down on the first update (or after possible unexpected delays).
For even better results, you may want to combine this technique with requestAnimationFrame() so that your timers won't needlessly fire while the user is e.g. looking at another tab:
function oncePerSecondAnim(callback) {
var frameFunc = function () {
// get the current time rounded down to a whole second (with a 10% margin)
var now = 1000 * Math.floor(Date.now() / 1000 + 0.1);
// run the callback
callback(now);
// wait for the next whole second
setTimeout(timerFunc, now + 1000 - Date.now());
}, timerFunc = function () {
requestAnimationFrame(frameFunc);
};
timerFunc();
}
// create a demo timer
oncePerSecondAnim(function (now) {
document.getElementById('local').textContent = new Date(now).toString();
});
// add an artificial 0.5 second delay for the second timer
setTimeout(function () {
oncePerSecondAnim(function (now) {
document.getElementById('utc').textContent = new Date(now).toUTCString();
});
}, 500);
<p>The local time is now: <span id="local">...</span></p>
<p>The UTC time is now: <span id="utc">...</span></p>
I am making an AJAX call in my code. What i want is to hit the AJAX call at 20th second of every minute. This is the AJAX request that i am making.
setInterval(function(){
$.ajax({
url: url,
headers: { 'x-cyclops-ajax': 'yes' },
method: 'POST',
dataType: 'json',
success: function(data) {
var chart = $('#container').highcharts();
var keys = Object.keys(data["histData"]);
$( "#main-div" ).empty();
for( var i=0; i< keys.length; i++) {
chart.series[i].setData(data["histData"][keys[i]]["histFailure"], true);
$('#main-div').append( '<div class="homepage-availability-inner-div"><h1 class="homepage-availability-text"> ' + keys[i] + ': <span class="dashboard-success">' + data["availData"][keys[i]] + ' </span> </h1></div>');
}
chart.xAxis[0].setCategories(data["histKeys"]);
console.log("Data:" + JSON.stringify(data["availData"]));
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("Did not hit the AJAX call");
}
});
}, 5000);
Any help would be appreciated.
If you mean only on the 20th second as in 13:00:20, 13:01:20 , 13:02:20, ...
you would have to do something like this:
// the interval can be set lower depending on the use case, to be more accurate
// Warning a too low interval setting might kill the performance of the browser/client,
// and execute the ajax multiple times, if the milliseconds are not considerate
let interval = 1000;
// the function is called (about) every second,
// so approximately 60 times per minute and executes the ajax call only once.
setInterval(
function(){
let now = new Date();
// should only fire, if it is the 20th Second in the current minute
if(now.getSeconds() === 20){
//ajax call
console.info(now);
}
}, interval
);
The Code check every Second, if it is the 20th Second. The performance might be a bit heavy for the client, doing some many calls, but it works.
Just to think about:
It could be optimized with changing the inertval, after a hit or higher interval length, or using setTimeout instead, and calculating, the next time to call it self.
btw.:
If you want to get the milliseconds also, you would have to put the interval lower and also query the getMilliseconds() function of the now Variable, but this would probably kill the performance of the client.
here is the link to the relevant Reference to the Date function getSeconds
here is a explanation on how/why the timeout/interval is not accurate, but there are also other reasons.
Optional (just4fun):
If you want do less setInterval calls, you could use setTimeout and call the function recursively, the "problem" being, how to tweak the time setting to get close to the 20th seconds without missing it.
Here is a small basic example, to start from:
(Yes the code isn't very optimized, and could be better structured, but I hope it gives a rough idea)
// the 20th Second, when the ajax call should execute
const selectedSecond = 20;
// can be tweaked to hit closer to 20th Second (ms)
let shortInterval = 400;
// depence on the size less calls are made
let safetyBuffer = 2;
// helper Variable, 60 Seconds
let sixtySeconds = 60;
// timeout value which is set dynamic, first time will execute "immediately"
let currentTimeout = 0;
function timeoutHandler(){
// gets current Time
let now = new Date();
let seconds = now.getSeconds();
if(seconds === selectedSecond){
// **** here the ajax call should go ****
console.info("ajax Called!!");
// sets the next timeout 58s later, not to miss the 20th Second
currentTimeout = (sixtySeconds - safetyBuffer) * 1000;
}else if(seconds > selectedSecond){
// sets the next timeout to 2s beforethe 20th Second
currentTimeout = (sixtySeconds - safetyBuffer - seconds + selectedSecond) * 1000;
} else if(seconds < selectedSecond - safetyBuffer) {
// sets the next timeout to 2s beforethe 20th Second
currentTimeout = (selectedSecond - safetyBuffer - seconds) * 1000;
} else {
// sets the next timeout to shortInterval(=400ms),
// for the last 2s, it will be more often, to not miss the 20th second
currentTimeout = shortInterval;
}
// calls the function with the new optimized timeout
setTimeout(timeoutHandler, currentTimeout);
}
// initial call
setTimeout(timeoutHandler, currentTimeout);
You can use setInterval method for continuous loop and when current second is 20 you can make ajax call. Please see the code snippet:
setInterval(function() {
if(new Date().getSeconds() === 20) {
// Your ajax call
}
}, 1000);
I have a simple stopwatch timer included in my Ionic app (Android). I basically just save the start date, and then check every second (mytimeout = $timeout($scope.onTimeout, 1000);) how many seconds it's been since that time. This works fine, but whenever I press the home button and then reopen the app (resume), it shows the old time for a fraction of a second, before updating to the new time. This does't happen when you exit the app and reopen it, because then it just calculates the new time.
Anyone who can help me with this? Any help is appreciated.
Update: countdown code:
$scope.onTimeout = function() {
$scope.clock=Math.trunc(timeleft());
mytimeout = $timeout($scope.onTimeout, 1000);
};
//timer counts down from 60 seconds
function timeleft()
{
var currentdate = new Date();
var currentdateseconds = currentdate.getTime()/1000;
var timeleft = 60 - (currentdateseconds - window.localStorage['seconds']);
return timeleft;
}
I seem to be having some unexpected results with a framerate counter in javascript. Up until recently the counter has been fine and I have been running my little js app at 30fps.
It uses setTimeout() (with a time adjustment to counter the system 'falling behind').
window.requestAnimFrame = (function()
{
return function (callback) {
time += FPS;
Heartbeat._eTime = (new Date().getTime() - Heartbeat._start);
var diff = Heartbeat._eTime - time;
Heartbeat._delta = FPS - diff;
Heartbeat._deltaS = Heartbeat._delta / 1000;
window.setTimeout(callback, FPS - diff);
};
})();
Heartbeat is merely an object that contains the frame rate info.
*Here is my problem: *
_MainLoopHandler: function () {
timer = new Date().getTime();
counter = timer;
while (this._messages.length > 0 && (counter - timer) < 5)
{
// process messages from _messages array
}
counter = new Date().getTime();
// THE ABOVE IS HAPPY AT 30 FPS
while ((counter - timer) < 6) {
1 + 1;
}
// THE ABOVE WHILE IS VERY UNHAPPY :(
}
So the above code block is the function that is called from setTimeout every 33.33 milliseconds (30 fps). if I take the bottom while loop out, the FPS counter will sit happily at 30fps. However, if I leave it in, the FPS counter goes crazy. it goes up to the 200FPS 300FPS then suddenly goes -200FPS -10FPS 0.01FPS. Its completely off the wall. The while loop will only run maybe 10 times per "frame".
Note also, the hard-coded values 5 and 6 are simply a check to see if 5 or 6 milliseconds have passed while processing the loops (for load balance).
Is this simply javascript being unable to handle the amount of info or has anyone else had a similar problem.
Thanks!
I don't really know what's going on, but I think you should use local variables to control your time, constantly reassess counter and process 1 message at a time. Also, I don't really understand that last loop (I've also renamed the variables):
_MainLoopHandler: function () {
var start = new Date().getTime();
var current;
do {
if (this._messages.length === 0) break;
// process 1 message
current = new Date().getTime();
} while (current - start < 5);
}
You can also encapsulate the timing concern in an object (not shown) to streamline the code:
_MainLoopHandler: function () {
var timing = new Timing();
do {
if (this._messages.length === 0) break;
// process 1 message
} while (timing.elapsed() < 5);
}