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>
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?
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);};
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 web page with transitions, On click everything goes to opacity:0 ( 1 second duration ) and then a new page is swapped in and everything goes to opacity:1 ( 1 second duration )
It ends up looking weird if the page doesn't have exactly 1 second to hide and appear. Also if the page doesn't get swapped immediately in between the two it looks award.
This was my first code
$('#main').css('opacity', '0');
setTimeout(function(){
$('#main').load('/views/'+name+'.html').css('opacity', '1')
}, 1000);
however load() sometimes takes too long to grab the view, and since the css is implemented immediately the opacity is already 1 when it swaps in.
so I tried this:
$.get('/views/'+name+'.html', function(page){
setTimout(function(){
$('#main').html(page).css('opacity', '1')
},1000);
})
But now if the $.get() is slow, the page is blank for too long.
Ideally I would like to know how long the promise took to fulfill, and subtract that from the setTimeout time.
I am thinking now that I have to manually create a new date object and check the difference after promise fulfillment.
Is there a better solution?
I forgot I can just use promises.
var pagePromise = $.get('/views/'+name+'.html')
$('main').css('opacity', '0')
setTimeout(function(){
pagePromise.then( function(page){
$('main').html(page).css('opacity', '1') }
)
},1000)
Just get time before and after your request. This may not be exact, but the error margin can easily be ignored for most purposes, yours included.
var time = Date.now();
$.get('/views/' + name + '.html', function(page) {
var elapsed = Date.now() - time;
setTimout(function() {
$('#main').html(page).css('opacity', '1')
}, 1000 - elapsed);
})
You can use Date.now() and calculate the difference.
var start = Date.now();
$.get('/views/' + name + '.html', function(page) {
setTimout(function() {
$('#main').html(page).css('opacity', 1);
}, 1000 - (Date.now() - start));
});
It's a little hard to tell exactly what you're trying to accomplish, but attempting to follow your logic, it appears that you want your new content to show up in one second after you hid the old content except when the content takes longer than that to load in which case, it shows up when it's loaded. You can do that by breaking the process down into a couple steps.
Record the starting time.
Fetch your content with ajax
When the content has been fetched, check how much time has elapsed.
If more than a second has elapsed, then just insert the content and show it.
If less than a second has elapsed, then set a timer for the remaining amount of time and then show the content when that timer fires.
You can implement that logic like this:
var begin = Date.now();
var main = $('#main').css('opacity', '0');
$.get('/views/'+name+'.html').then(function(content) {
main.html(content);
var elapsed = Date.now() - begin;
if (elapsed > 1000) {
// show it now
main.css('opacity', '1');
} else {
setTimeout(function(){
// show it when 1 second has finished
main.css('opacity', '1');
}, 1000 - elapsed);
}
});
Using this sort of notification and time measurement scheme, there is no guessing about load times.
You can use ajax and make your code synchronous.
jQuery.ajax({
url: '/views/'+name+'.html',
success: function (result) {
$('#main').html(page).css('opacity', '1');
},
async: false,
type: "GET"
});
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);
}