clearInterval doesnt stop loop - javascript

I have the following code
startProgressTimer: function () {
var me = this,
updateProgressBars = function (eventItems) {
alert("updateProgressBars: looping");
alert("me.eventProgressTimerId:" + me.eventProgressTimerId);
var i = 0;
if (eventItems.length === 0) {
alert("internal Stop Begin")
clearInterval(me.eventProgressTimerId);
alert("internal Stop End")
eventItems = [];
}
for (i = 0; i < eventItems.length; i++) {
if (eventItems[i]._eventId) {
eventItems[i].updateProgressBar();
}
}
};
alert("Start Progress Timer");
this.eventProgressTimerId = setInterval(function () {
updateProgressBars([]);
}, 10000);
}
When the function is called I would expect it to run and bottom out only it keeps on looping.
screen output
ALERT:updateProgressBars: looping
ALERT:me.eventProgressTimerId:10
ALERT:internal Stop Begin
ALERT:internal Stop End
ALERT:updateProgressBars: looping
ALERT:me.eventProgressTimerId:10
ALERT:internal Stop Begin
ALERT:internal Stop End
Any ideas

I suspect the problem might be that the code you don't show calls the startProgressTimer() method more than once for the same instance of whatever object it belongs to, and then within the method you store the interval id in an instance property this.eventProgressTimerId - so multiple calls overwrite the property and you'd only be able to cancel the last one.
If that's the case, a simple fix is to declare your eventProgressTimerId as a local variable within startProgressTimer().

Related

How to stop a function when it's called?

I'm building a program that either counts down or up and I've got it working however I like to press count-up in the middle of count down or vice versa and I like the counter to stop and count up or vice versa. how do I achieve that? thanks a lot for your help :)
function myFunctionUp() {
var Timer = setInterval(function () {
i++;
document.getElementById("mydata").textContent = i;
if (i >= 21)
clearInterval(Timer);
if (i == 21){
document.getElementById("mydata").textContent = "Boom-up!";
}
}, 1000);
}
function myFunctionDown() {
var Timer = setInterval(function () {
i--;
document.getElementById("mydata").textContent = i;
if (i <= 0)
clearInterval(Timer);
if (i == 0){
document.getElementById("mydata").textContent = "Boom-down";
}
}, 1000);
}
Use a variable to keep track of the way to count. When a button is clicked, invert the value of the variable :
let countDown = 10;
let increment = -1;
function count() {
countDown += increment;
document.getElementById('container').innerText = countDown;
setTimeout(() => count(), 1000);
}
document.getElementById('btn').addEventListener('click', function () {
increment = -increment;
});
count();
Working stackblitz here
You typically never "take control" on the execution of another method. When you want to do that, the logic must be inverted. The function itself must ask if it should continue.
With an example : let's take a function which works in an infinite loop, that you want to be able to stop on demand. In some languages, you could run some code in a thread and interrupt the thread on demand. But even if it is possible, it is generally a bad idea to stop some code at the middle of its execution.
A better way of doing that is to create a "should Continue ?" piece of code at the end of the iteration. It could read a variable or call a method etc. When you want to stop the iteration, you just have to set this variable and you know that the infinite loop will stop graciously at the end of the current iteration

How to disable function when another function is called?

I wish to disable the opacity fade out function when stop win function is running. I'm using Typescript. How can I do that? Your kindness help is appreciated.
Method that I tried:
Add if statement that include setTimeout function, but it show stopBigWinAnimation type is void
Add if statement that include setTimeout function, declare Boolean type for stopBigWinAnimation and add a return, however Uncaught RangeError: Maximum call stack size exceeded
// Stop Win function
public stopBigWinAnimations() {
this.mainContainer.opacity = 255
let animBigWin4 = this.nodes4.getComponent(sp.Skeleton);
// Maybe it is not animated or it is the 0th empty node
if (animBigWin4) {
animBigWin4.clearTracks();
animBigWin4.setToSetupPose();
if (animBigWin4.defaultAnimation) {
animBigWin4.setAnimation(0, animBigWin4.defaultAnimation, true);
}
}
}
// Fade Out function
setTimeout(function () {
this.nodes5.opacity = 0;
this.nodes6.opacity = 0;
this.nodes7.opacity = 0;
this.nodes8.opacity = 0;
}.bind(this), 6500);
Expect Result: While Stop Win Function, Fade out function is being disable.
If I understand correctly, you want to disable the setTimeout when stopBigWinAnimations is called.
To do that, you need to name the setTimeout (fadeOutFunction) so you can "clear" it whenever your stopBigWinAnimations function runs.
let fadeOutFunction = null;
public stopBigWinAnimations() {
clearTimeout(fadeOutFunction);
this.mainContainer.opacity = 255
let animBigWin4 = this.nodes4.getComponent(sp.Skeleton);
// Maybe it is not animated or it is the 0th empty node
if (animBigWin4) {
animBigWin4.clearTracks();
animBigWin4.setToSetupPose();
if (animBigWin4.defaultAnimation) {
animBigWin4.setAnimation(0, animBigWin4.defaultAnimation, true);
}
}
}
// Fade Out function
fadeOutFunction = setTimeout(function () {
this.nodes5.opacity = 0;
this.nodes6.opacity = 0;
this.nodes7.opacity = 0;
this.nodes8.opacity = 0;
}.bind(this), 6500);

User interaction conflict during SetTimeout in Javascript

I am working on a WordPress (Javascript) plugin that alters text fields based on user interaction with an HTML5 slider. One of its effects is to reveal a <span> string one character at a time using SetTimeout to create a delay (a few ms) so the effect is perceptible. I'm accomplishing this by getting the DOM element's contents and then rebuilding it one character at a time.
The problem is that since SetTimeout is aynsynchronous, the user can potentially move the slider faster than a single reveal loop can complete, resulting in half-empty DOM elements that never get corrected.
Is there a way to prevent this, or alternatively, a way to accomplish the task that avoids the conflict altogether? I have tried turning off the EventListener (for the HMTL5) at various points in the delay loop but cannot find a place that avoids the issue. The other possibility is to load all the <span> contents into arrays in order to retain intact copies of everything ... but something tells me there's a better way to do it that I don't know.
Here is example code. Initialize() is called when the HTML page involved loads.
function Initialize () {
document.getElementById(name).addEventListener('input', UpdateSlider);
}
function UpdateSlider()
{ if (
// conditions
)
{ var cols = document.getElementsByClassName(attr+i);
RevealTextLines (cols);
}
// 'delay' is a global variable to set the delay length
function RevealTextLines (cols)
{
[].forEach.call(cols, function(el) {
var snippet = el.innerHTML;
el.innerHTML = '';
el.style.display = 'inline';
(function addNextCharacter(h) {
el.innerHTML = snippet.substr(0,h);
h = h + numchars;
if (h <= snippet.length) {
setTimeout(function() {
addNextCharacter(h);
}, delay);
}
})(1);
});
}
The boolean flag suggested above does not work in this case, but it did inspire the following solution:
Provided the number of iterations are known in advance (which in this case they are), define a global counter variable outside the functions. Before the SetTimeout loop, set it to the number of iterations and decrease it by 1 every time through. Then have the calling function proceed only when the counter's value is zero.
var counter = 0;
function Initialize () {
document.getElementById(name).addEventListener('input', UpdateSlider);
}
function UpdateSlider()
{ if ( counter == 0)
{ var cols = document.getElementsByClassName(classname);
RevealTextLines (cols);
}
function RevealTextLines (cols)
{
[].forEach.call(cols, function(el) {
timer = el.length;
var snippet = el.innerHTML;
el.innerHTML = '';
el.style.display = 'inline';
(function addNextCharacter(h) {
el.innerHTML = snippet.substr(0,h);
h++;
if (h <= snippet.length) {
setTimeout(function() {
addNextCharacter(h);
timer--;
UpdateSlider();
}, delay);
}
})(1);
});
}
If anyone knows a more efficient solution, I would remain interested.

starting & stopping timers: using 1 function for multiple instances

This is code used within nodered.
I'm invoking several timers with the same function, then either the timer actually runs and displays something,
or I stop the timer (clearTimeout) and the something doens't get displayed.
The first thing I tried is this:
// multiple calls method 1 - DOES NOT WORK (multiple calls of procedure with same name - no method to distuinguish
function displaysomethingelse7 (rdelay7, var37, var47) {
function performactualstuff (var3a7, var4a7) {
node.warn ("37:"+var3a7+", 47:"+var4a7);
}
timer7=setTimeout(performactualstuff, rdelay7, var37, var47);
node.warn ("starting timer27_inprocedure: "+timer7._idleStart);
function stop7() {
if (timer7) {
clearTimeout(timer7);
node.warn ("stopping timerid27 "+timer7._idleStart);
timer7 = 0;
}
}
return stop7;
}
// start 1
delay20=8500;
var20a=2;
var20b="b";
var t10 = displaysomethingelse7 (delay20, var20a, var20b);
// start 2
delay21=10500;
var21a=3;
var21b="c";
var t11 = displaysomethingelse7 (delay21, var21a, var21b);
// stop 1 ?
stopdelay30=8000;
setTimeout(t10, stopdelay30);
// stop 2 ?
stopdelay31=9000;
setTimeout(t11, stopdelay31);
This doens't work since the 'stop7' function has no method to disguinguish between timerIDs.
So I came up with an array of functions:
// multiple calls method 2 - array of functions
function displaysomethingelsetoo (r2delay, var77, var88) {
function performactualstufftoo (var77a, var88a) {
node.warn ("77:"+var77a+", 88:"+var88a);
}
timer8=setTimeout(performactualstufftoo, r2delay, var77, var88);
node.warn ("starting timer77_inprocedure= "+timer8._idleStart);
if (typeof stopa === 'undefined') stopa=[];
stopa[timer8._idleStart] = function (tf) {
if (tf) {
clearTimeout(tf);
node.warn ("stopping timerid3 "+tf._idleStart+"originaltimer="+timer8._idleStart);
tf = 0;
}
}
return stopa[timer8._idleStart];
}
// start 1
delay3=4000;
var5a=4;
var6a="d";
var t3a = displaysomethingelsetoo (delay3, var5a, var6a);
// start 2
delay4=5000;
var5b=5;
var6b="e";
var t3b = displaysomethingelsetoo (delay4, var5b, var6b);
// stop 1 ?
stopdelay3=2000;
setTimeout(t3a, stopdelay3, t3a);
// stop 2 ?
stopdelay4=3000;
setTimeout(t3b, stopdelay4, t3b);
But this isn't quite correct yet either - the stopa array has all the same function in it.
I think the solution could be to pass the parsed timer8 variable to the stopa[timer8._idleStart] function,
but I have no idea how to to do this.
This doens't work since the 'stop7' function has no method to disguinguish between timerIDs
You will want to use a closure here. I think you already tried to use one, and your code is structured like you were using one, there's only a tiny modification necessary: declare the variable as local to the displaysomethingelse7 function so that each invocation will create a new variable.
function displaysomethingelse(rdelay, a, b) {
function performactualstuff() {
node.warn ("37:"+a+", 47:"+b);
// btw, you'll want to close over a and b here as well
}
var timer = setTimeout(performactualstuff, rdelay);
// ^^^
node.warn ("starting timer_inprocedure: "+timer._idleStart);
return function stop() {
if (timer) {
clearTimeout(timer);
node.warn ("stopping timer "+timer._idleStart);
timer = 0;
}
};
}

Have a JS function call destroyed after one time use

I'm working on quite a unique project and have a variable that calls my function, is it possible to have it where after it makes 1 function call, it stops working and becomes useless.
var limiter = function (limit, cb) {
var counter = limit;
return function () {
if (counter > 0) {
cb(counter);
counter--;
}
};
};
var counting = limiter(3, function (data) {
console.log('This function can be used ' + data + ' more times.');
});
for (var i = 0; i < 5; i++) {
counting();
};
Calling limiter with the first paramater as 1 and the second parameter as the function definition will allow you to run the function only one time. In this example, I have created the function 'counting' that will log how many more calls it has until it is useless (It only run three times, despite the for loop calling it five times). The for loop at the bottom just shows that it works. You can also create multiple functions using limiter, without the counters overlapping, as they will each have their own unique scope.
Fiddle: http://jsfiddle.net/Kajdav/acLxxywt/

Categories