I have a setInterval function, which displays the remaining time for an event on my website. But the countdown is not in sync with the actual tick of the second.
My code uses an ajax call to the server to get the expiry date once, and on its success the countdown will start. Great till there.
var request = new XMLHttpRequest();
request.open('GET', 'https://my-website/service.php', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
date = request.responseText;
timer = setInterval(showRemaining, 1000);//start the countdown
} else {
// We reached our target server, but it returned an error
}
};
But the time when setInterval is called needs to be in sync with actual global tick of the second.
(I hope I make sense. I mean the calls need to be in sync with each time a second passes in your PC's or phone's clock!)
How can I achieve that? Thanks in advance!
You need to make an initial setTimeout with the difference between the current ms and the next ms, ie:
1000-(new Date().getMilliseconds()))
then you can start the setInterval
Note that setTimeout/setInterval has a minimum value (generally considered 10ms), so if it's less than that value to the next second, add 1000.
Also note that setTimeout/setInterval are not 100% accurate, but for the nearest second will likely suffice.
This gives your success code:
date = request.responseText;
var t = 1000-(new Date().getMilliseconds());
if (t < 15) t+=1000;
setTimeout(function() {
timer = setInterval(showRemaining, 1000);//start the countdown
}, t));
As #freedomn-m suggested in the comments, 1000-(new Date().getMilliseconds()) is the key piece of code I was looking for - the difference between the current ms and the next ms. So my code is now working and it looks like this:
if (request.status >= 200 && request.status < 400) {
date = request.responseText;
setTimeout(function() {
timer = setInterval(showRemaining, 1000);//start the countdown
}, 1000-(new Date().getMilliseconds()));//to make the calls in sync with actual tick of the second
}
Related
I am making a game where there is a 5 seconds countdown, I am doing this countdown on the server side. I want the timer to start over and over again when I send it the request it will respond with the current timer value. For example if 2.2 seconds has passed when the request is made it sends 2.8 seconds as a response and so on. Below you can see my code at the moment, thanks in advance!
router.get("/:result", (req,res) =>{
const result = JSON.parse(req.params.result)
var timerTime = {
time: null
}
if(result.message == "startNewTime"){
//Start the timer
}else if(result.message == "checkingTime"){
//Get the timer value and set it to be the timerTime.time value
//Start the timer from 5 seconds again
res.send(JSON.stringify(timerTime))
}
})
Have you tried setTimeout() ?
You can pass the function or result as first argument and milliseconds as second parameter.
Then you can approach it differently! Try setting a simple counter.
let counter = 0
for(let i = 0; i < 5; I++){
setTimeout(counter++, 1000)
}
Maybe it works this way? You can only track seconds this way though, not milliseconds.
I got it working. The problem I had with the date.now() method was that I was sending a new request and the variable value reset ofc so I just saved it to the session and got it working. Thanks bye!
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 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'm working on a chatbot script (Hubot - running in terminal) exercise and looking for a method to count the time since the last message was left in the thread. Then after nobody has left a message for X number of minutes (let's say 10,000 milliseconds) I would like to console.log("CRICKETS!..CRICKETS!..")
I'm imagining something like:
//currentTime - startTime = timeSince
//and
// if( timeSince > 10,000)
// {console.log("Crickets!..")
however I'm not sure of how to create the currentTime variable as continuously growing counter
Below is the code I've started which doesn't appear to throw any errors in the , but also doesn't seem to work as I'm running it in the terminal. It just prints the current time twice
module.exports = function(robot) {
return robot.hear(/$/i, function(msg) {
var startTime = (Date.now()) ;
return(startTime);
if (Date.now() - startTime > 1000) {
console.log("CRICKETS..!...")
};
});
};
You'll notice I'm using Date.now() but I'm not attached if there's a better method. Also here is a link to basic hubot scripts in case it is needed for context - https://github.com/github/hubot/blob/master/docs/scripting.md
You can always use setTimeout and cancel it if need be
Pseudo-code:
var myTimeout = setTimeout(function () {
//nobody has left a message for 10 seconds
}, 10000);
if (user has left message)
clearTimeout(myTimeout);
The window.setTimeout function allows you to trigger a callback function after a delay. And you can clear that timeout by calling window.clearTimeout(value_returned_by_setTimeout).
We could define a callback: function crickets(){ console.log('Chirp! Chirp!'); }
Assuming some function newMessage gets called whenever a a new message appears, you could try something like this:
var cricketTimeout = null;
function newMessage(){
//... your code
if (cricketTimeout) clearTimeout(cricketTimeout);
cricketTimeout = setTimeout(crickets, delayInMilliseconds);
}