Wait for something to stop to trigger function - javascript

I'm using a date picker I created with the sly tool darsa.in and everything is perfect, except that if the user changes the days too fast JavaScript does not trigger the correct date for the function.
Is there a way for doing:
if (datepicker not active for x seconds)
Or is there a way to create a variable and trigger the function only if that variable does not change during x time? I need to give some time to JS so it does not trigger the function until the user is on the date he targets.
Some code follows below.
When the day of the day picker changes, I call loadDateMatches() which loads all the matches into the HTML. But if you change, for example, very quickly between day 1 and day 5, it may stop loading the matches on day number 3.
I'm looking for a way to not trigger the function loadDateMatches() until there has been some time without changing the date.
days.on('active', function (eventName) {
activeDate= this.rel.activeItem;
var logDate = new Date(d.getFullYear(), 0, activeDate + first + 1);
var startTime = new Date(logDate.getFullYear(), logDate.getMonth(), logDate.getDate(), 0, 0, 0);
DayBarConditions.startTime = startTime.getTime()/1000;
var endTime = new Date(logDate.getFullYear(), logDate.getMonth(), logDate.getDate(), 23, 59, 59);
DayBarConditions.endTime = endTime.getTime()/1000;
if (typeof loadDateMatches == 'function') {
loadDateMatches();
}
});

Try having the date picker call a function on a delay that first checks whether the set day is the same as when it was changed, then loads the info if so. I believe the below code should be functional, however it is untested.
days.on('active', function (eventName) {
activeDate= this.rel.activeItem;
// We have to put this in a separate function, so that it evaluates activeDate
// when the date picker is changed, not when activateDelayed is called
(function(activeDate) {
//Activate the function after .5 seconds if date remains unchanged
window.setTimeout(activateDelayed, 500, activeDate);
})(activeDate);
};
function activateDelayed (oldDate) {
activeDate = days.rel.activeItem;
if (oldDate == activeDate) {
var logDate = new Date(d.getFullYear(), 0, activeDate + first + 1);
var startTime = new Date(logDate.getFullYear(), logDate.getMonth(), logDate.getDate(), 0, 0, 0);
DayBarConditions.startTime = startTime.getTime()/1000;
var endTime = new Date(logDate.getFullYear(), logDate.getMonth(), logDate.getDate(), 23, 59, 59);
DayBarConditions.endTime = endTime.getTime()/1000;
if (typeof loadDateMatches == 'function') {
loadDateMatches();
}
}
});

You could use this code, which keeps track of the number of requests you have for executing loadDateMatches. When it is the first one, the function is executed immediately, but the request counter is not decreased until also the cool-down period has passed. Only then is the counter decreased. While that counter is 1, another request can be added, but it will only lead to an execution when the first cool-down period has expired. Any more requests during that cool-down period will not change anything -- at the most one request will be pending for execution after the cool-down:
var requests = 0;
days.on('active', function (eventName) {
// ... your existing code, setting DayBarConditions properties, comes here.
// ...
if (typeof loadDateMatches == 'function') {
// Keep track of number of requests
if (requests < 2) requests++;
// Ignore this when there is currently a cool-down ongoing, and
// another execution is already pending:
if (requests == 2) return;
(function loop() {
loadDateMatches();
setTimeout(function () {
// Cool down has passed: repeat when new request is pending
if (--requests) loop();
}, 500);
})();
}
});
So, this code will not delay the very first request, but introduce a cool-down period during which any further requests are joined into one, and which will only execute when that cool-down period has expired.
But there may be better solutions depending on which code you have running in loadDateMatches.

Related

Double interval call and it should not be in node.js

I have problem on server side (node.js) with setInterval.
I want to check something every day at specific time and I set interval like this:
let maintainTime = backFunc.getNextMaintainTime(new Date());
let maintain = setInterval(() => {
let currentTime = new Date();
if (currentTime.getTime() > maintainTime.getTime()) {
maintainTime = backFunc.getNextMaintainTime(maintainTime);
//do the maintain
}
}, 360000);
//360000 to check on every hour
and here is my getNextMaintainTime function:
getNextMaintainTime: (maintainTime) => {
maintainTime.setDate(maintainTime.getDate() + 1);
maintainTime.setHours(4);
maintainTime.setMinutes(0);
maintainTime.setSeconds(0);
maintainTime.setMilliseconds(0);
return maintainTime;
}
When I test it out it works perfectly but when I start server on production every time it calls this function 2 times instead of 1 time at 4am, what could cause the problem?

Javascript: Know when an actual second is ticked?

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
}

Make AJAX call on 20th second of every minute

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);

JS variable containing ongoing time value

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);
}

Console output one time every 40 seconds with interval doesn't work

I'm trying to use Twitter API in order to retweet.And because Twitter has limitation to 2400 actions per day I decided to limit the retweet to one time every 40 seconds.
I'm using https://www.npmjs.com/package/twit using Streaming API.
My problem is that it continuously streams console.log instead of using setInterval.
By stream I mean it outputs console.log multiple times instead of one time.
function hastagRetweet() {
var stream = T.stream('statuses/filter', { track: ['#hastag']})
stream.on('tweet', function (tweet,error) {
var retweetId = tweet.id; // id
var retweetId_str = tweet.id_str;
var tweetTextRetweet = tweet.text; // tweet text
function twInterval() {
console.log('INFO ------- ',tweet.id);
console.log('INFO ------- ',tweet.text);
};
setInterval(twInterval, 1000 * 40);
});
}
Any way of getting the variales data retweetId,retweetId_str,tweetTextRetweet outside stream.on beside inserting them into a mysql table so that every 40 seconds it checks the variables fixed data and executes console.log?
There are multiple problems here:
You're trying to start an interval timer in an event handler. That means that every time the event fires you would be attempting to start a new interval timer and they would pile up.
Even if you did sucessfully start up an interval timer, each one would never change it's output since the variables in scope for it never change as it is started up within a given function and the arguments to that function are what they were when it was first called. Subsequent calls of the function will start a new function not change the arguments on the prior call of the function.
You aren't even starting your interval correctly. As it is, all you're doing is calling the function and passing it's return value to setInterval() which does nothing.
If the goal is just to output to the console each stream tweet event, then probably what you want is just this:
function hastagRetweet() {
var stream = T.stream('statuses/filter', { track: ['#hastag']})
stream.on('tweet', function (tweet,error) {
var retweetId = tweet.id; // id
var retweetId_str = tweet.id_str;
var tweetTextRetweet = tweet.text; // tweet text
console.log('INFO ------- ',tweet.id);
console.log('INFO ------- ',tweet.text);
});
}
You cannot get these variables outside the .on() handler. It's an async callback and the only place they reliably exist is within that handler.
If you can describe in more detail what the end result you're trying to achieve is, we can likely help more specifically. If you want to do something every 40 seconds, then maybe you need to collect data in some collection (probably an array) and then every 40 seconds evaluate what you have just recently collected.
Here's a method of collecting the events in an array and then evaluating them every 40 seconds:
function hastagRetweet() {
var stream = T.stream('statuses/filter', { track: ['#hastag']});
var tweets = [];
stream.on('tweet', function (tweet,error) {
tweets.push({id: tweet.id, str: tweet.id_str, text: tweet.text});
});
setInterval(function() {
// evaluate the tweets in the tweets array every 40 seconds
// do something with them
for (var i = 0; i < tweets.length; i++) {
// tweets[i].id
// tweets[i].str
// tweets[i].text
}
// reset the tweets array
tweets.length = 0;
}, 40 * 1000);
}
Please note that once you call hastagRetweet(), it will run forever.

Categories