setTimeout() function being called twice in a row - javascript

I am writing a bot that sends alerts at variable intervals. I am using setTimeout() and I have an issue I can't seem to be able to figure out. The (simplified) code is:
//Original call to setTimeout():
timeout = setTimeout(issueAlarm, 2147483647); // highest possible interval setTimeout() will accept.
//In bot:
// dh is a priority queue that keeps timestamps sorted from smaller to larger as the user requests alerts.
//'mom' is a moment.js variable that holds the most recent request.
//This block of code checks the PQ and if what the user just entered is smaller than what is already stored, it updates the timeout.
//This seems to work fine
// First get input from user and store the desired time of first alert in 'mom'. Then:
var nextD = dh.peekNext();
if (nextD.timestamp >= mom.valueOf() ){
var now = new Date();
clearTimeout(timeout);
timeout = mom.valueOf() - now;
setTimeout(issueAlarm, timeout);
}
//issueAlarm function:
function issueAlarm() {
var next = dh.getNext(); // this pops the first alarm from the queue
// here goes some code that issues message. Then:
var peek = dh.peekNext(); // this looks at the next element in the queue without popping it
if (peek) {
var now = new Date();
timeout = peek.timestamp - now;
setTimeout(issueAlarm, timeout);
}
}
The example inputs are:
First input entered: Set an alert every 8 hours starting 5 minutes from now ("call Bob")
Second input entered: Set an alert every 8 hours starting 4 minutes from now ("call Jane")
In 4 minutes, i correctly get "call Jane" (this one gets set from the bot code)
One minute later, I correctly get "call Bob", but also i get "call Jane" (which should not happen until 8 hours later)
I printed all the timeout values and they seem correct. I also am printing the return of the setTimeout() function inside the issueAlarm() function.
Inside the first call: _idleTimeout: 59994 (this is correct, the next call is in one minute)
Inside the second call: _idleTimeout: 28739994 (this looks correct, it's approximately 8 hours, but still i get a third call right away)
Inside the third call: _idleTimeout: 28799991 (this timeout looks correct but this function call shouldn't have happened)
I'm using botFramework. My knowledge of JavaScript and node.js is far from extensive. I have printed out everything I could think of, but I can't figure out why that third call is being made right away.
This happens only if the first input entered requests an alert that starts later than the one entered in the second input. But I can't possibly understand why.

I thought you could have a problem with the Next function that returns you the data, take a look to my example. If your function is returning the next element as they were saved, you could not use that function, you need to build a function that return the first alarm to call. Hope it helps!
var dh = {};
dh.alarms = [{time: 1000, name:"Jane"},{time:5000, name:"Jane"},{time: 3000, name:"Bob"}];
dh.first = function(){
dh.alarms = dh.alarms.sort(function(a,b){return a.time - b.time});
next = dh.alarms.slice(0,1);
dh.alarms = dh.alarms.slice(1);
return next[0]
}
dh.next = function(){
next = dh.alarms.slice(0,1);
dh.alarms = dh.alarms.slice(1);
return next[0]
}
var timeout = setTimeout(executeAlarm, 2999999);
function start(){
var next = dh.first(); // dh.next(); I thought this is your problem!!
if(next && next.name){
clearInterval(timeout);
timeout = setTimeout(function(){executeAlarm(next)},next.time);
}
}
function executeAlarm(next){
if(!next || !next.name) clearInterval(timeout)
document.getElementById("alarms").innerHTML += "<span> Alarm for " + next.name + "</span>";
start();
}
document.addEventListener( "DOMContentLoaded", start, false );
<div id="alarms"></div>

(Posted on behalf of the OP).
The problem was here, in the bot code:
if (nextD.timestamp >= mom.valueOf() ){
var now = new Date();
clearTimeout(timeout);
timeout = mom.valueOf() - now;
setTimeout(issueAlarm, timeout);
}
I was clearing the timeout correctly the first time (when i cleared the original timeout of 2^31 - 1), but not afterwards. The issue is that the line in which i call setTimeout should be
timeout = setTimeout(issueAlarm, timeout);
So that the return is stored in a timeout object. I was making subsequent calls to clearTimeout() by passing a value, not an object, and therefore the timeout stored first (5 minutes, 'call Bob') was never cleared.
Thanks to #guest271314 and to #damianfabian for helping me get to the correct answer.

Related

onkeyup activates many ajax requests

In an entry I use the onkeyup function so that every time I type it, I activate a javascript function, which makes requests to the server using ajax, the problem arises when the user types quickly, so with each key that he / she touches, activates an ajax request which causes me many requests, and also brings me bad results.
I do not know if it is understood, I hope someone can give me an idea of ​​how to change this.
Thank you
This kind of ajax call is not good idea.
Anyhow,
You should do ajax call when user has typed at least 3-4 letters.
You can also add some a check to see if user has typed something and stopped writing then do the ajax.
If you still want to do ajax on each character then try to do very light ajax means get very small data from server.
Check if input length is > 3:
var userInput = $('#inputFiled').val(); // get user input and save into js variable
if(userInput.length > 3){ //if user input is at least 3 characters
//do ajax here
}
To check if user has stopped writing
To do so you will have to use underscore.js
$('#userInout').keyup(_.debounce(yourAjaxCallFunctionHere , 500));
underscorejs.org/#debounce
You can also achieve this using jQuery
var delayInAjaxCall = (function(){
var timer = 0;
return function(callback, milliseconds){
clearTimeout (timer);
timer = setTimeout(callback, milliseconds);
};
})();
Usage Of Above Function
$('input').keyup(function() {
delayInAjaxCall(function(){
alert('Hi, func called');
}, 1000 );
});
You can utilize the below JS code and achieve with few lines of codes,
let timer = null;
on_key_up(){
//if input length < 3 return it
if(timer){
window.clearTimeout(timer);
timer = null;
}
timer = window.setTimeout( ()=>{
FireMyEvent()
}, 1000);
}

Knockout setTimeout delay

When a user logs into my website, I store a "logged in until" parameter on my server for that user, which is updated each time they interact with the server. So if they are inactive for X seconds, they should be logged out and the page on their client refreshed to show the login screen. Everything works nicely except the function keeps calling itself at 1 second intervals, and not the 1700+ second interval I'm looking for. As each call hits the server, I don't want this to keep running more often than it needs to.
This function is contained within my knockout viewmodel. logoutTimer is declared as a global variable. Watching the console log I can see the delay shows the correct time, but it seems to be running about every 1 second.
self.autoLoginCheck = function() {
clearTimeout(logoutTimer);
//If not, refresh the main screen => that'll push them to the login screen automatically
myurl = "/api/checkLoginStatus.php";
var parameters = {
'userPublicID':self.userInfo().userPublicID
}
$.post(myurl, parameters, function(data) {
var getResponse = JSON.parse(data);
if (getResponse.loggedIn < 1 ) {
//This is the log out condition
location.reload(true);
} else {
//Check how many more seconds the current log in is good for, that's when we'll check it again
var msdelay = getResponse.nextCheck * 1000;
console.log("Delay is " + msdelay);
logoutTimer = setTimeout(self.autoLoginCheck(), msdelay);
}
});
}
I know this type of question has been asked many times, but reading all those answers I can't see why this function is running every second and not waiting 30 minutes. Thanks to whoever shows me the obvious!
The first parameter to setTimeout should be a function, not the result of a function.
logoutTimer = setTimeout(self.autoLoginCheck, msdelay);

how to get an event's completion time in jquery

hi i am using jquery .
i have a check box click event
jQuery('.btn-check-box').click(function () {
//code goes here .
});
the problem is the click event takes considerable time to complete.some times the browser gets stuck.
so i want to change the code inside the function and reduce the completion time .
now i want to get my current click event completion time .
then make changes to the code and again check the completion time .
so i can optimize my code according to the completion time .
is there any way to check an events completion time .
please help.
thanks in advance.
Pass event as argument.
var createdTime;
jQuery('.btn-check-box').click(function(e){
createdTime = e.timeStamp;
}).done(function(){ calculate time difference });
if you will use console.log(e) then it will show you that jQuery already passing timestamp when event is triggered.
so now you need to find a way when even is getting done so .done() jQuery method will help you.
In side .done() you can also get same e.timestamp and do some math on to get your desired out put in second, minutes or anything.
Like SrinivasR said, finish time - start time.
jQuery('.btn-check-box').click(function () {
var t0 = (new Date()).getTime();
//code goes here
console.log("Event took",(new Date()).getTime() - t0, "ms to complete.");
});
Try the following for your code
jQuery('.btn-check-box').click(function () {
var secondStart = new Date().getTime() / 1000;
// Your code goes here .
var secondEnd = new Date().getTime() / 1000;
var totalTime = secondEnd - secondStart;
console.log('Executing took' +totalTime +'seconds' )
});

How to have a timer which cannot be modified in javascript?

Basically, I am designing a quiz application with limited time. Use selects answer to a question and the next question loads using an Ajax request. All questions must be answered within a time frame of, say 2 minutes.
A clock ticks away to show how much time is left and as soon as it hits 0, results are shown. Now since the timer will be implemented using window.setTimeout(), it is possible that the value of timer variable be modified using an external bookmarklet or something like that. Anyway I can prevent this? I think this is implemented on file sharing sites like megaupload. Any forgery on the timer variable results in request for file being rejected.
Have .setTimeout() call an AJAX method on your server to synch time. Don't rely on the client time. You could also store the start time on the server for a quiz, and then check the end time when the quiz is posted.
You need to add a validation in your server side. When the client want to load the next question using an Ajax request, check whether deadline arrived.
The timer in client side js just a presention layer.
If the function runs as a immediately called function expression, then there are no global variables and nothing for a local script to subvert. Of course there's nothing to stop a user from reading your code and formulating a spoof, but anything to do with javascript is open to such attacks.
As others have said, use the server to validate requests based on the clock, do not rely on it to guarantee anything. Here's a simple count down that works from a start time so attempts to dealy execution won't work. There are no global variables to reset or modify either.
e.g.
(function (){
// Place to write count down
var el = document.getElementById('secondsLeft');
var starttime,
timeout,
limit = 20; // Timelimit in seconds
// Function to run about every second
function nextTick() {
var d = new Date();
// Set start time the first time
if (!starttime) starttime = d.getTime();
var diff = d.getTime() - starttime;
// Only run for period
if (diff < (limit * 1000)) {
el.innerHTML = limit - (diff/1000 | 0);
} else {
// Time's up
el.innerHTML = 0;
clearTimeout(timeout);
}
}
// Kick it off
timeout = window.setInterval(nextTick, 1000);
}());

jQuery event only every time interval

$(document).ready(function() {
$('#domain').change(function() {
//
});
});
The code inside the change function will basically send ajax request to run a PHP script. The #domain is a text input field. So basically what I want to do is to send ajax requests as user types in some text inside the text field (for example search suggestions).
However, I would like to set a time interval in order to lessen the load of PHP server. Because if jQuery sends AJAX request every time user adds another letter to the text field it would consume lots of bandwidth.
So I would like to set let's say 2 seconds as an interval. The AJAX request will be fired every time the user types a letter but with maximum frequency of 2 seconds.
How can I do that?
$(function() {
var timer = 0;
$("#domain").change(function() {
clearTimeout(timer);
timer = setTimeout(function(){
// Do stuff here
}, 2000);
});
});
$(document).ready(function() {
var ajaxQueue;
$('#domain').change(function() {
if(!ajaxQueue) {
ajaxQueue = setTimeout(function() {
/* your stuff */
ajaxQueue = null;
}, 2000);
}
});
});
What you really want to do is check how long since the last change event so you keep track of the number of milliseconds between events rather than make a call every 2 seconds.
$(document).ready(function() {
var lastreq = 0; //0 means there were never any requests sent
$('#domain').change(function() {
var d = new Date();
var currenttime = d.getTime(); //get the time of this change event
var interval = currenttime - lastreq; //how many milliseconds since the last request
if(interval >= 2000){ //more than 2 seconds
lastreq = currenttime; //set lastreq for next change event
//perform AJAX call
}
});
});
Off the top of my head without trying this in a browser. Something like this:
$('#domain').change(function() {
if (!this.sendToServer) { // some expando property I made up
var that = this;
this.sendToServer = setTimeout(function(that) {
// use "that" as a reference to your element that fired the onchange.
// Do your AJAX call here
that.sendToServer = undefined;
}, yourTimeoutTimeInMillis)
}
else {
clearTimeout(this.sendToServer);
}
});
two variables, charBuffer, sendFlag
Use a setTimeout to have a function be called every two seconds.
This function checks if the buffer has stuff in it.
If it does, it sends/empties the stuff and clears the sent flag (to false).
and It should also clear the timeout, and set it again
else it sets the flag (to true).
Everytime the user hits a key, store it in the buffer.
if the sent flag is clear (it's false), do nothing.
else (it's true) send/empty the stuff currently in the buffer and clear the flag (to false),
and It should also clear the timeout, and set it again
This will make it so that the first time you press a key, it is sent, and a minimum of 2 seconds must pass before it can send again.
Could use some tweaking, but i use this setup to do something similar.
I am coming across this problem more and more (the more i do UI ajax stuff) so i packaged this up into a plugin available here

Categories

Resources