I have a small issue clearing an interval with Javascript.
I've searched for the mistake that I've made but I couldn't find any.
Variable declarations:
let i, interval;
let currentLoops = 0;
let settings = {
amount:0,
loops:0,
speed:0};
Where i make my interval:
$('#start').click(()=>{
getSettings();
let interval = setInterval(setColorGrid, settings.speed);
});
How i tried to clear it:
if(currentLoops == settings.loops){
clearInterval(interval);
console.log("interval cleared");
}
If you have any ideas/suggestions for this comment below.
Remove the let part from the event handler. It causes to create a handler function scoped interval variable which shadows the outer interval variable.
$('#start').click(() => {
getSettings();
interval = setInterval(setColorGrid, settings.speed);
});
Related
I know that this question has been asked before on this platform, but I am really unable to implement the same thing that this friend implemented *(I mean Roy's answer).
How will I pause the timer, mean (clear interval) from an outside function?
according to my algorithm the function checkAnswer (should) be out side of the fetchQuesiton() function, It's not a big problem if it was inside but it's better for me to be outside, Help as much as you can.
[edit] more explain:
let's imagine that a player is playing this game, so when the timer reaches to 0, and the player until now didn't choose any answer, it will then clear that timer and then move to the checkAnswer function, which will then check for no answer, this means (in the future, when I make it) that it (checkAnswer) will return false, mean the answer is incorrect.
another case, is when the player chooses an answer, it will pauses that setInterval timer, and check for the answer if it was correct or incorrect.
function theCallerFunction() {
fetchQuesiton();
//this is just an overview from a code I am writing.
}
var fetchQuesiton = async() => {
//this function should be async because later it will check a value responded by a promise.
//start timer
let timer = 15;
const startTimer = setInterval(() => {
timer--;
console.log(timer);
if (timer == 0) {
clearInterval(startTimer);
console.log("TIMEUP! YOU'RE LOSER!");
checkAnswer();
}
}, 1000);
//[click] on chances
let options = document.querySelectorAll('.option');
options = Array.prototype.slice.call(options);
options.forEach(cur => {
cur.addEventListener('click', checkAnswer);
});
}
var checkAnswer = async() => {
//this function should be async because later it will check a value responded by a promise.
clearInterval(startTimer);
console.log("I am working!");
}
theCallerFunction();
<div class="option">a)</div>
<div class="option">b)</div>
<div class="option">c)</div>
<div class="option">d)</div>
The variable startTimer inside the checkAnswer function block doesn't refer to the same value as startTimer inside the fetchQuesiton.
Move startTimer out of fetchQuestion so that both variable call refer to the same value.
let startTimer
var fetchQuesiton = async() => {
...
startTimer = setInterval(() => {
Variables in javascript is lexically scoped. Read more here What is lexical scope?
Move startTimer to the global scope - or at the very least, a greater scope.
function theCallerFunction (){
fetchQuesiton();
//this is just an overview from a code I am writing.
}
let startTimer;
var fetchQuesiton = async ()=>{
//this function should be async because later it will check a value responded by a promise.
//start timer
let timer = 15;
startTimer = setInterval(()=>{
timer--;
console.log(timer);
if(timer == 0){
clearInterval(startTimer);
console.log("TIMEUP! YOU'RE LOSER!");
checkAnswer();
}
},1000);
//[click] on chances
let options = document.querySelectorAll('.option');
options = Array.prototype.slice.call(options);
options.forEach(cur=>{
cur.addEventListener('click', checkAnswer);
});
}
var checkAnswer = async () => {
//this function should be async because later it will check a value responded by a promise.
clearInterval(startTimer);
console.log("I am working!");
}
theCallerFunction();
<div class="option">a)</div>
<div class="option">b)</div>
<div class="option">c)</div>
<div class="option">d)</div>
I am trying to implement a stopwatch. When the start button is pressed setInterval is called. How can I stop by running clearInterval when the stop button is pressed, without having a global variable to pass as a parameter to clearInterval
<body>
<p class="clock">00:00:00</p>
<button class='start'>Start</button>
<button class="stop">Stop</button>
<script>
let totalMilliSeconds = 0;
function tick(){
totalMilliSeconds++;
let hours = Math.floor(totalMilliSeconds/3600)
let minutes = Math.floor(totalMilliSeconds/3600)
let seconds = Math.floor(totalMilliSeconds/360)
document.querySelector('.clock').textContent = `${hours}:${seconds}:${totalMilliSeconds}`
}
function start(){
return setInterval(tick,1)
}
document.querySelector('.start').addEventListener('click',start)
document.querySelector('.stop').addEventListener('click',start)
</script>
<p>
</body>
</html>
You're clearly going to need to store the reference to the interval somewhere. It's not clear what you mean by not having a global variable; one solution would be to declare it at the top:
let totalMilliSeconds = 0;
let interval = null;
function tick(){
totalMilliSeconds++;
let hours = Math.floor(totalMilliSeconds/3600)
let minutes = Math.floor(totalMilliSeconds/3600)
let seconds = Math.floor(totalMilliSeconds/360)
document.querySelector('.clock').textContent = `${hours}:${seconds}:${totalMilliSeconds}`
}
function start(){
if (!interval) interval = setInterval(tick,1);
return interval;
}
function stop() {
if (interval) clearInterval(interval);
interval = null;
}
document.querySelector('.start').addEventListener('click',start)
document.querySelector('.stop').addEventListener('click',stop)
Thanks to JS scopes, the variable interval will be available in all functions declared in the script.
You just need to use the Interval ID returned by setInterval(). In your case, you could do something like that:
let intervalId;
document.querySelector('.start').addEventListener(
'click',
() => {intervalId = start();}
);
Then you can do clearInterval(intervalId) whenever you want.
If you want to avoid global variables you can wrap the whole thing in function declaration, then call it immediately. Any variables declared with var or let will only exist within the function's scope.
Example using Christoph's code sample:
(function() {
let totalMilliSeconds = 0;
let interval = null;
function tick(){
totalMilliSeconds++;
let hours = Math.floor(totalMilliSeconds/3600)
let minutes = Math.floor(totalMilliSeconds/3600)
let seconds = Math.floor(totalMilliSeconds/360)
document.querySelector('.clock').textContent = `${hours}:${seconds}:${totalMilliSeconds}`
}
function start(){
if (!interval) interval = setInterval(tick,1);
return interval;
}
function stop() {
if (interval) clearInterval(interval);
interval = null;
}
document.querySelector('.start').addEventListener('click',start)
document.querySelector('.stop').addEventListener('click',stop)
})();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
This is for frontend Javascript linked to an HTML file if that's relevant. I tried using IIFE for this problem and a bunch of things broke, so I'd like to avoid trying again if possible. I declared a timer that I want to stop conditionally (i.e. backend sends front end a message to stop or timer ticks for thirty seconds, whichever comes first), but I'm not sure how to do this without globally declaring a timer variable.
Here's some dummy code because the actual thing is around 300 lines:
const startTimer = ()=>{
let time = 30
const timer = setInterval(()=>{
if(time === 0){
clearInterval(timer)
}
}
},1000)
}
startTimer()
socket.on('stop-timer', ()=>{
//I want to clear the timer when this gets emitted.
})
How would I avoid declaring a global timer? Is it really that bad to do so?
You could create a simple class (I assume you use ES6 by the look of your code) that will expose cancel method to clearInterval like this:
class Timer {
constructor(time) {
this.time = time;
this._interval = null;
}
start() {
this._interval = setInterval(...);
}
cancel() {
clearInterval(this._interval);
this._interval = null;
}
}
const timer = new Timer(30);
timer.start();
socket.on('stop-timer', timer.cancel);
I want to change the setTimeout speed while running the function.
I think im almost there, there is something still not work on my script. but i can't figure out what.
Can someone help me ?
$('input[type="range"]').rangeslider({
polyfill: false,
onInit: function() {
this.update();
},
onSlide: function(pos, value) {
tempPosition = pos + this.grabX;
position = (tempPosition <= this.handleWidth) ? this.handleWidth : (tempPosition >= this.maxHandleX) ? this.maxHandleX : tempPosition;
//timer = setTimeout(counter, value);
//clearTimeout(timer);
//var speed = value;
//clearTimeout(timer);
var timer = 0;
timer.length = 0;
timer = setTimeout(counter, value);
clearTimeout(timer);
document.getElementById("demo").innerHTML = timer;
//alert(counter);
}
});
var counter = function() {
imagesArray[i].setOpacity(0.00);
i++;
if(i > 23){
i = imagesArray.length - 23;
}
imagesArray[i].setOpacity(0.60);
speed = parseInt(speed);
setTimeout(counter, speed);
document.getElementById("test").innerHTML = speed;
};
counter();
First, I'll try and point out some problems with your code Inside the onSlide callback, you have:
var timer = 0;
timer.length = 0;
timer = setTimeout(counter, value);
clearTimeout(timer);
So, every time the slider is used, you initialize the local variable timer to 0. You never use this value so this is not meaningful. In fact, it would be enough to break your logic, but there are other problems too. Then, you try to set the length property of timer to 0. Surely this must cause a runtime error? Numbers have no length property. Then you assign timer the id that setTimeout() returns, which is all well, but then, you immediately clear the timeout, preventing the scheduled counter() invocation from ever being executed.
The counter function, on the other hand, calls itself using setTimeout, but the ID that is returned is not captured, meaning this scheduled invocation will execute regardless of what you do inside the onSlide callback.
Then I don't see where the speed variable is defined or set.
Basically, there are too many problems with your code to go through them all in the scope of an answer. A sound approach would probably look something like this:
var timer, speed; //Global, or at least in a scope shared by both the onSlide callback and the counter function
$('input[type="range"]').rangeslider({
...
onSlide: function() {
clearTimeout(timer); //Cancel the currently pending execution of counter();
speed = ... //Read value from slider
timer = clearTimeout(counter, speed);
},
...
});
var counter = function() {
...
timer = setTimeout(counter, speed);
...
};
It's worth noting that with this approach, as long as the slider is adjusted before the timeout has passed, counter() won't get to execute.
I am using setInterval(); function to run a function every 5 sec, but i want to clear this interval if
some condition satisfied.
function do_the_job(){
//some code
if(some_condition)
{
clearInterval(interval);
}else{
clearInterval(interval);
var interval = setInterval(do_the_job(),5000);
}
}
function clearInterval(); is not working here.
In your code the var interval =... is local, not visible outside the scope of the function call, and thus will not work in a recursive function.
Make the interval a global variable, and it will work.
solution
var interval;
function do_the_job(){
//some code
if(some_condition)
{
clearInterval(interval);
}else{
clearInterval(interval);
interval = setInterval(do_the_job(),5000);
}
}
Make interval a global or 'higher scoped' variable by moving its declaration outside the if statements, so that it's actually in scope when clearing.
This is not a good time to use setInterval(), try setTimeout() instead
function do_the_job(){
//some code
if(some_condition)
{
// job done
}else{
setTimeout(do_the_job,5000);
}
}
var interval = setInterval(do_the_job(),5000);
Should be no parethesees
var interval = setInterval(do_the_job,5000);