interval keeps firing even though clearInterval has been called - javascript

I am trying to get a function to run 10 times with a pause inbetween each run, yet when I try to it repeats the function infinite times then after 10 times it pauses, and so on. Right now this is the code with the problem:
for(i=0;i<10;i++) {
console.log(i);
interval = setInterval(function() {console.log("Function ran");}, 1000);
}
window.clearInterval(interval);
Console:0123456789Function ran["Function ran" is repeated infinite times after "9"]

interval = setInterval(function() {console.log("Function ran");}, 1000);
This line creates a new interval-instance each time, which means you have created 10 intervals. At the end of the loop interval holds the id of the last interval that was created. Hence that's the only one you're clearing, and the other ones are still running.
To cancel the interval, you need to keep track of how many times the function has been invoked. One way you can do that is as follows:
function pauseAndRepeat(delay, iterations, func) {
var i = 0;
var interval = setInterval(function() {
func();
if(++i === iterations) {
clearInterval(interval);
}
}, delay);
}
Here we have a function that defines a counter (i) in its local scope. Then it creates an interval using a function that checks the counter to see if it should call your function (func) or clear the interval when it is done. interval will have been set when the interval-handler is actually called. In this case the handler is basically a closure since it is bound to the local scope of pauseAndRepeat.
Then you can invoke the function as follows:
pauseAndRepeat(1000, 10, function() {
console.log("Function ran");
});
This will print out Function ran ten times, pausing for a second each time.

setInterval is expected to run forever, on an interval. Every time you call setInterval here, you have a new infinite loop running your function every 10s, and as others have noted you only are canceling the last one.
You may do better with chained setTimeout calls:
var counter = 0;
function next() {
if (counter < 10) {
counter++;
setTimeout(function() {
console.log("Function ran");
next();
}, 1000);
}
}
next();
This chains delayed functions, setting a timeout for the next one after each runs. You can do something similar with setInterval and cancellation:
var counter = 0;
var intervalId = setInterval(function() {
console.log("Function ran");
if (++counter >= 10) {
clearInterval(intervalId);
}
}, 1000);
In both these cases the key issue is that you trigger the next run or cancel the interval within the callback function, not in synchronous code.

Related

setTimeout in JS

function x() {
for (let i = 1; i <= 5; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
console.log("Hello World!!");
}
x();
The above function produces the output 1 to 5 but it's taking 1 second to produce each output. And that's what I am not getting... Why is it taking 1 second each and why not 1 second for first value of i, then 2 seconds for second value of i and so on and so forth as I am multiplying the milliseconds with the i value?
The main confusion you are having is pretty common and comes from the fact that you are using a loop. Everything outside of the timer callback is JavaScript that is being executed synchronously with no delay. The loop executes 5 times immediately when you run the code and so 5 instances of the timer callback function get placed on the event queue in a matter of milliseconds and it is from that point in time that all 5 timer callbacks are delayed, rather than one callback being delayed from the completion of the prior one.
The first instance of the callback then runs after its initial delay is reached (1 second), then the second instance runs after its delay (2 seconds, which is only 1 second later than when the first function call ran) and then the third one runs (which is only 1 second behind the previous one of 2 seconds) and so on.
What you need to do is place the first instance of the callback on the event queue with a 1 second delay before it runs and then, when that first instance has completed, place another instance on the event queue with a 2 second delay, and so on.
To do this, forget the loop and make the timer function recursive, which will essentially cause a repeating code call, just as a loop would.
let delay = 1000;
let timer = null; // Will hold a reference to the timer
function x() {
timer = setTimeout(function(){
console.log(delay / 1000);
delay += 1000;
if(delay > 5000){
clearTimeout(timer); // Cancel the timer
console.log("Operation Complete!");
} else {
// Because the next call for the parent function comes from within
// the timer callback function, it is delayed until the end of that
// callback function's execution.
x();
}
}, delay);
}
x();
If you want the behaviour of adding a i seconds each time, do something like:
function x(i, max = Infinity) {
if (i > max) return
console.log("Hello World!! %s", i);
setTimeout(function() {
console.log(i);
x(i + 1, max)
}, i * 1000);
}
x(1, 5);

How to use setInterval to trigger a function so that I can stop it at some point?

So from what I have understood, setInterval() is used to call a function on repeat on regular intervals.
So basically it is a loop that executes a function forever periodically.
I am confused as to if I had to stop this execution at one point what would be the way to do it
for eg I am trying to print the message "hey" 3 times after 1 second each, but somehow it is printing it 3 times every second and is going on forever.
What can I do to stop it after a set number of times.
This is the code that I've been trying
var i = 3;
function message() {
console.log("hey");
}
while(i > 0) {
setInterval(message, 1000);
i = i - 1;
}
Your code is executing the setInterval thrice in the while loop, which is not needed.
Actually, setInterval does not work as a function call but actually registers a function to be called at some interval.
The setInterval() method will continue calling the function until clearInterval() i.e it is deregistered or the process is killed.
It should work like this
var i = 3;
var interval = setInterval(message, 1000);
function message() {
if (i === 0) {
clearInterval(interval);
}
console.log("hey");
i = i - 1;
}
To clear a setInterval, use global clearInterval method.
Example:
var timerId = setInterval(func, 500);
.... some code here....
clearInterval(timerId);
What can I do to stop it after a set number of times.
usually you don't use setInterval() for this, you use setTimeout().
Something like
var counter = 0;
function message() {
console.log("hey");
// we trigger the function again after a second, if not already done 3 times
if (counter < 3) {
setTimeout(message, 1000);
}
counter++;
}
// initial startup after a second, could be faster too
setTimeout(message, 1000);
The setInterval function calls the function indefinitely, whereas setTimeout calls the function once only.
Simply use clearInterval once the count runs out.
var i = 3;
function message(){
console.log("hey");
if (--i < 0) {
clearInterval(tmr);
}
}
var tmr = setInterval(message, 1000);
you have to assign that setInterval to a javascript variable to name it what for this setInterval, like this
var messageLog = setInterval(message, 1000);
After, in setInterval message function add this condition to clear the inverval whenever you want to clear.
function message(){
if(i>3) {
clearInterval(messageLog); // clearInterval is a javascript function to clear Intervals.
return null;
}
console.log("hey");
}
You can retrieve the timer when creating and clear it if needed.
var i=3;
var timer = setInterval(message,1000);
function message(){
console.log("hey");
i—-;
if(i==0)
clearInterval(timer)
}
a beginner here too,look for clearInterval method ...

Javascript function setTimeout and setIntervall not working

I've got this Problem here, that this function is not working and I cant figure out why..
This function should count to 10 (in 10 seconds). For this purpose I'm using a for loop with setTimeout function - duration set to 1000ms.
It should go on and on for what i took the setInterval function.
function timer() {
var time=10;
for(i=0; i<time; i++){
setTimeout(console.log(i+1), 1000);
}
}
setInterval(timer, 10000);
The Problem is, that it isnt working and I dont understand why ... I have found another working solution but would like to know the issue of this one. :)
The reason that nothing appears to happen is the way that you use setTimeout. Instead of providing an event handler you are calling console.log and try to use the return value from that call as event handler.
The closest thing that would at least do something would be to make a function that calls console.log:
setTimeout(function(){ console.log(i+1) }, 1000);
However, you will notice that it will just log the value 11 ten times at once, every ten seconds, indefinitely.
Eventhough the loop counts from 0 to 9, you start a timeout in each iteration that will be triggered one second from when it was created. As all ten timeouts are created at the same time, they will be triggered at the same time. There isn't a separate variable i for each handler, so they will all show the value in the variable at the time that they are triggered, and as the loop has completed before any of them can be called they will all show the final value 10 + 1.
You are using both an interval and timeouts, you should use one or the other.
You can start timeouts in a loop, but then you should only do it once, not in an interval, and you should specify the time from start to when you want it to be triggered:
var time = 10;
for (var i = 1; i <= time; i++){
setTimeout(function() { console.log('tick'); }, 1000 * i);
}
If you want to use the variable in the event handler, then you need to create a copy of the variable for each iteration:
var time = 10;
for (var i = 1; i <= time; i++){
(function(copy){
setTimeout(function() { console.log(copy); }, 1000 * i);
})(i);
}
You can use an interval, but then you don't have a loop, it's the interval that is the loop. Use clearInterval to stop it when you reach the end of the loop:
var i = 1, time = 10, handle;
function timer() {
console.log(i);
i++;
if (i > time) clearInterval(handle);
}
handle = setInterval(timer, 1000);
First, it's not working because setTimeout call is wrong. Even if your setTimeout call worked, there's another issue here. Your code will actually print 11 every 10 seconds.
function timer() {
var time = 10;
for (i = 0; i < time; i++) {
setTimeout(function() {
console.log(i + 1)
}, 1000);
}
}
setInterval(timer, 10000);
Because, you have sequential setTimeout calls to be effected every second and you are forming a closure on the variable i.
You need to take care of the closure and calls must be done after the second has been printed.
function timer() {
var p = Promise.resolve();
for (var i = 0; i < 10; i++) {
p = p.then(closure(i));
}
}
function closure(i) {
return (function () {
return new Promise(function (resolve) {
setTimeout(function () {
document.getElementById('results').innerHTML = (i + 1) + '\n';
resolve();
}, 1000);
})
});
}
timer();
setInterval(timer, 10000);
<pre id="results"></pre>
When I run your code in the Firebug debugger, I see:
TypeError: can't convert console.log(...) to string
I added a comment to your code about that error:
function timer() {
var time=10;
for(i=0; i<time; i++){
// The source of error is the line below
// Type error: setTimeout needs a function as first argument!
setTimeout(console.log(i+1), 1000);
}
}
setInterval(timer, 10000);
A corrected version might be
function timer() {
var time=10;
for(i=0; i<time; i++){
setTimeout(function() { console.log(i+1); }, 1000);
}
}
setInterval(timer, 10000);
However, the above change fixes the type error but not the logic.
You probably wanted to do this:
var counter = 0;
var count = function() {
console.log(++counter);
if (counter >= 10) {
clearInterval(timer);
}
};
var timer = setInterval(count, 1000);
Once the callback function count notices the counter passed the value 10 it will stop the periodic timer whose ID was saved in the variable timer when setting it up.

Define a timer in JavaScript

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

Why is my javascript for loop not working?

fourI am writing a javascript for loop and am sure have done a terrible job:
init = function () {
var i = 0;
timer = setInterval(function () {
if (i >= 4) {
clearInterval(timer);
return;
}
for (i = 0; i < 10; i++) {
console.log('init fired');
}
}, 2000);
};
init();
What I want is for the timer to stop after the i variable in the for loop reaches four. Instead the log is showing init fired ten times. What am I doing wrong?
I think you need it like this
var i=0; //Global Declaration
init = function(){
timer = setInterval(function(){
console.log('init fired');
i++;
if(i>4){
clearInterval(timer);
return; }
}, 2000);
};
init();
Hope this solves your problem. This will trigger init() method four times as you have expected and if the i reaches 4 the interval will be cleared.
Every time the timeout handler runs, it starts "i" back at zero.
The problem with your "for" loop is basically that you should not use a "for" loop :-)
Those 10 iterations are happening on the first pass through the function. After that first pass, "i" will be 10 and so the "if" condition will cancel the timeout. However, that "if" check is only made at the beginning of the function, so the loop will always complete 10 iterations.
If you want to have just four iterations of the timer (or five or whatever), you'd just leave off the "for" loop, and add i++; after the console log message. That way, the timer would issue one log output when it runs, and when that's happened the number of times you desire, it will stop.

Categories

Resources