I am doing some long polling (ajax) and I am looping the following portion of code.. There is code being executed above and below. This code is part of an internal messaging system. A certain portion of the page wil blink when a message arrives. If the user checks the message, it will remove the dash_notify from the JSON response, which needs to turn off the blinking. See below:
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
timer = setInterval(blink, 10);
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
}
console.log("initiate_dash");
blinking($(x));
} else if (!data.dash_notify) {
console.log("good");
clearInterval(timer);
}
The following JSON response that gets sent to this code is:
{"current_date_time":"January 8, 2013 - 4:02 pm","dash_notify":"1"}
It understand the initial blink IF the above data gets passed. If the following gets passed:
{"current_date_time":"January 8, 2013 - 4:02 pm"}
Then it throws an error:
Uncaught ReferenceError: timer is not defined
I cannot figure out how to fix the "else" portion working properly. If the code is initiated when the full dash_notify:1 response is sent, it works perfect. The button will blink, then if the user checks the message, it will no longer send dash_notify:1 and the button stops blinking. But if the code is initiated when dash_notify:1 is NOT set, it doesn't know what to do with the ClearInterval.
Basically I need the else portion fixed.
I have tried using different typeOf === undefined snippets, but it doesn't work.
Any help is appreciated.
Thank you!
EDIT:
This is currently working.. Timer is now defined above the statement
if(data.dash_notify == '1'){
var x = '#dash_notif_blink';
console.log("initiate_dash");
blinking($(x));
}else if (typeof timer != "undefined" && timer) {
clearInterval(timer);
}
}
This is working, but sometimes it trys to kill the timer but it doesn't actually do it. This happens every so often.
Looks like it's not working because timer doesn't exist outside your inner blinking function. I'm making an assumption here that you don't have var timer; somewhere outside the blinking function, which is strongly likely given the error you're getting.
Why this is happening:
If I'm right, and you're not declaring timer anywhere else in your code, then var timer is being implicitly added to the beginning of the blinking function:
function blinking(x) {
var timer;
timer = setInterval(blink, 10);
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
}
That makes timer a local variable inside blinking. Since you never pass it out of the closure, it doesn't exist once you're outside that function. So either you need to pull timer into the outer context (option 1) or make it available from inside blinking (option 2).
What to do:
If you want access to timer outside of that closure, you'll have to do one of two things:
1: Declare timer outside of blinking:
var timer = null;
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
//etc...
2: Make it the return value of blinking:
var t;
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
var timer = setInterval(blink, 10); //note the var keyword for best practice
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
return timer;
}
console.log("initiate_dash");
t = blinking($(x));
} else if (!data.dash_notify) {
console.log("good");
clearInterval(t);
}
Either one of these will work, and is more or less the same in terms of polluting the outer namespace. I prefer Option 2, because I feel like it's easier to work with a local variable until you need to return it.
Edit:
Your comment said the loop runs infinitely, which means you're creating a brand new interval and reassigning the timer variable every time. This is a separate problem from the one I described above. The old interval is still out there, timer just doesn't point to it anymore. So how can clearInterval(timer) clear out all those intervals? It can't, it can only clear the most recent one.
Basically, you've got a whole bunch of timers all trying to make the thing blink at once.
How you deal with this depends on what you're trying to do. The simplest thing would be to keep no more than one interval running at once, which means you have to clear timer every time.
//same as option 1 above except for `clearInterval(timer)` at the
//beginning of `blinking`
var timer = null;
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
clearInterval(timer);
timer = setInterval(blink, 10);
If you need multiple timers running, you'll have to keep track of them all in an array or something:
var timers = [];
//...
function blinking(x) {
timers.push(setInterval(blink, 10));
//...
} else if (!data.dash_notify) {
timers.forEach(function(timer) {
clearInterval(timer);
});
}
Not sure what you did wrong with your typeof check since you did not actually show the whole code, but it should look something like this:
if (typeof timer != "undefined" && timer) {
clearInterval(timer);
}
Basically define your variable timer before you enter your checking procedure (loop?):
var timer;
... some code ...
if ( data.dash_notify && data.dash_notify == '1') {
...
} else if (!data.dash_notify) {
clearInterval(timer);
}
You can call clearInterval( whatever ) without any consequences. Even if whatever is null, undefined, string and so on. Just make sure timer exist.
Passing an invalid ID to clearTimeout does not have any effect (and
doesn't throw an exception). (MDN)
You're getting that error because timer is only declared/initialized in the blinking function. In the place where you call clearInterval(timer), timer doesn't exist.
This is now working beautifully.
*Thank you to everyone who helped!*
if(data.dash_notify === '1' && t === null ){
var x = '#dash_notif_blink';
function blinking(x) {
var timer = setInterval(blink, 10); //note the var keyword for best practice
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
return timer;
}
console.log('initiate_dash_alert');
// Data is passed. Parse to see if dash alert should be called. Secondary protection for
// multiple timer creation.
if(t){return;}else{t = blinking($(x));}
}else if (!data.dash_notify){
clearInterval(t);
console.log('clear_dash_alert');
t = null;
}else{
console.log(t);
console.log('no_push_events');
}
Related
Was hoping to find some help complete this question.
logs the message parameter to the console every (Number Parameter). Implement an html button to start and stop this sequence.
In attempting the question I was able to get this so far.
var displayLog = function Container(param) {
var message = 'any string'; // Local message variable
var timeCount = "10"; // Local time count variable
setInterval(function getLoggeddemo(message,timeCount) {
console.log(message);
return getLoggeddemo;
}(), timeCount);
}
The question is asking to display a message every (x) seconds, when a button is toggled between start & stop. I'm currently trying to figure out how to include an if/else statement to start and stop the sequence with an Html button .
A few issues:
Don't call the function you want to pass to to setInterval: so remove the parentheses after the function body.
You never seem to call displayLog.
timeCount is supposed to be a number, not a string: it is the number of milliseconds the interval lasts.
There is no influence of the button clicks on the interval logic.
Returning something in a setInterval callback has no meaning. Also the arguments will not be provided to that callback: remove those parameters.
I would suggest not to add/remove event listeners, but to use a boolean variable that indicates the state you are in, and depending on that perform the appropriate action in one, single click handler:
var i = 0;
var displayLog = function Container(message) {
console.log(i++, message);
// Return the id of the interval
return setInterval(function getLoggeddemo() { // no arguments here
console.log(i++, message);
}, 1000); // Every second
}
var mixBut = document.getElementById("mixBut");
var interval = null;
mixBut.addEventListener("click", toggle);
function toggle(){
if (interval === null) {
mixBut.value = "Stop";
interval = displayLog("Hi there!");
} else {
mixBut.value = "Start";
clearInterval(interval);
interval = null;
}
}
<button id="mixBut">Mix</button>
I have a function in JavaScript. I use setInterval in order to control my function. I also have another logic for controlling my function. I have a counter which is increased once one condition happens and is decreased when another condition happens. Now, sometimes the second condition does not happen and hence my function won't be resume anymore. (I pause my function when my first condition happen). Therefore, I want to wait at most 30 seconds for the second condition. If it does not happen, then I want to resume my function anyway. I have following code, but it does not work as I expect it. What happens is that it resume my function every 30 seconds. Then, it may be resumed while it should wait. Can someone let me know what is the problem with my code?
Please note that, the value for the counter may increase to more than 20. I mean the first and second condition may occur more than once.
function main()
{
// body
}
function increaseCounter()
{
counter += 1;
clearInterval(controller);
controlSecond = setInterval(function(){
counterSeconds += 1;
if (counterSeconds == 30)
{
counterSeconds = 0;
controller = setInterval(main, 100);
clearInterval(controlSecond);
}
}, 1000);
}
function decreaseCounter()
{
counter -= 1;
if (counter == 0)
{
counterSeconds = 0;
clearInterval(controlSecond);
controller = setInterval(main, 100);
}
}
Consider what happens if you call increaseCounter twice in a row.
On the first execution it will create interval A and assign it to controlSecond.
On the second execution it will create interval B and assign it to controlSecond, while interval A continues to fire off indefinitely. You won't stop it with clearInterval(controlSecond) because controlSecond no longer references interval A.
The problem is that you continue to set controlSecond and controller to a new interval without clearing them first. That results in the intervals being leaked with no way of clearing them. It's sort of like a memory leak where you have dynamically allocated memory but nothing pointed at it, but instead of renegade memory you have renegade intervals.
One way to prevent this is to make sure you always clear your interval before setting it.
I would also recommend that you implement controlSecond with a setTimeout because that is designed for tasks which only happen once.
Why not
var counter = 0
var timeout = null
function main () {
clearTimeout(timeout);
timeout = null;
}
function increaseCounter () {
counter++;
if (!timeout)
timeout = setTimeout(main, 30*1000);
}
function decreaseCounter() {
counter--;
if (counter === 0)
main();
}
I am trying to do a infinite loop, but it only works if I include an 'alert' on it. My code looks like this:
while( tocontinue ){
// Some code
alert('Accept to continue');
}
On this way, the user has to click to hide the alerts (for example, on Chrome), and then the loop continues correctly by itself. I need to implement this without any alert. I also tried this:
while( tocontinue ){
// Some code
tocontinue = false;
setTimeout(function(){tocontinue=true},500);
}
And with "window.setTimeout" too, and without the word "function(){}", but it doesn't work. I tried everything: some implementations on JavaScript of a sleep() function, calling the function each X time with setInterval, answers 1 and 3 on this post... :/
Thank you very much for your time.
I'm trying to implement a genetic algorithm, and I want to stop it when I decide (with a button that puts the global variable "tocontinue" to false). Meanwhile, I want a infinite loop.
Well, you won't be able to combine a true infinite loop with user interaction as they'll both be dependent on the same thread being able to work on them exclusively. But, you can get close with a near-instant interval.
var interval = setInterval(function () {
// some code
}, 10);
Possibly grouping a few iterations together for each round:
var interval = setInterval(function () {
var limit = 5;
while (limit--) {
// some code
}
}, 10);
But, the interval will keep the iteration going as quickly as possible while still giving some idle time for user interactions, like clicking a particular button to clear the interval.
document.getElementById('stopButton').addEventListener('click', function () {
clearInterval(interval);
}, false);
Example: http://jsfiddle.net/coiscir/xZBTF/
setInterval() may be more useful here.
function updateLoop() {
//All the code goes here
}
setInterval(updateLoop,500);
var reader = new XMLHttpRequest() || new ActiveXObject('MSXML2.XMLHTTP');
function loadFile() {
reader.open('get', 'ccc.txt', true);
reader.onreadystatechange = displayContents;
reader.send(null);
}
function displayContents() {
if(reader.readyState==4) {
var el = document.getElementById('main');
el.innerHTML = reader.responseText;
var data = el.innerHTML;
}
}
for(var I = 7; I >1; i+=3);
console.log(i)
I need to invoke some function given number of times through given delays. How should I do - declare variable for timer and pass it to invoking function for stopping timer in some moment or in loop (n times) invoke setTimeout once ( or some another approach to skeep delay time once) or other.Thanks.
edit to fix syntax eror
var timerID = null;
var n = 5;
this.timerID = setInterval(function(){
funcToInvoke(n,timerID){
if(invokeNumber == n){
clearInterval(timerID);
return;
}
else { do something}
}
},delay)
Yes, the approach is common and better than calling setTimeout in a loop (with a fixed number of times). It is more performant than that and also more flexible, because the interval will be stopped dynamically (might check for a future condition).
However, your code is a bit messy. Fixed:
// Assuming we a have
// n
// delay
// funcToInvoke
// and execute in context of some object
var that = this,
numberOfInvokes = 0;
this.timer = setInterval(function() {
// "this" points to the global object
if (numberOfInvokes == n)
clearInterval(that.timer);
else
funcToInvoke(numberOfInvokes);
numberOfInvokes++;
}, delay);
Your current method has a syntax problem, you can't have a function parameter like this.timerID). In fact, you should remove the whole funcToInvoke declaration, and declare n and timerID as local variables, so they will be available to the closure. Like this:
// Don't forget to define n here!
var n = 5;
// Change timerID to local var instead of property
var timerID = null;
timerID = setInterval(function(){
if(invokeNumber == n){
clearInterval(timerID);
return;
} else {
//do something
}
// You can setTimeout again anywhere in this function if needed
}, delay);
If you want an approximate delay, setInterval is probably ok. If you want a more precise interval, then repeated calls to setTimeout are better as you can adjust the length of time to the next call based on the time since the last call.
E.g. for a clock ticking every second, you can do repeated calls to setTimeout, setting the lag to just after the next full second.
I am working on a way to autocomplete function to navigate through steps of a form. Here is the code that when 5 characters are entered into an input, it then moves to the next element. My delay is working great, but I don't have a way to stop it from completing if characters get deleted after 5 characters are entered. It just fires off the focus right after that no matter what has changed in the input.
Any thoughts?
var delay = (function(){
var timer = 0;
return function(callback, ms) {
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$('input').keyup(function(){
if($(this).val().length == 5) {
delay(function(){ $("#saveForm2").focus(); }, 2000 );
}
})
If you're looking for an easy way to associate a timeout instance with an element, consider using jQuery's .data() method.
Something like this.
$('input').keyup(function() {
var $th = $(this);
var data = $th.data();
if(data.timeout === undefined) {
data.timeout = null;
}
if ($th.val().length == 5) {
clearTimeout(data.timeout);
data.timeout = setTimeout(function() {
$("#saveForm2").focus();
}, 2000);
} else {
clearTimeout(data.timeout);
}
});
I don't think the way you were using the closure was quite right. I think you would need to assign the handler to the element inside the closure as well, so it has a local reference to the instance.
EDIT: Made a little more efficient with earlier stored reference to data().
Each time you call delay(), you clobber your timeout handle, which means that you can't manage it after the fact. It also means that you're going to fire off a request every time you hit 5 characters, if I read that correctly. Try something like this:
var delayTimer;
var nextField = function() { $("#saveForm2").focus(); }
$('input').keyup(function(){
clearTimeout(delayTimer);
if($(this).val().length >= 5) {
delayTimer = setTimeout(nextField, 2000);
}
})
That'll a) fire off no more than 1 request unless you wait more than 2 seconds between keystrokes, and b) will cancel any pending request if you drop back under 5 characters before the timeout expires. As a bonus, it won't create a whole mess of anonymous functions.