I have 5 divs that I want to change the color of when the function is called, however each time the function is called the time given in the set interval seems to decrease.
let runways = [runway1, runway2, runway3, runway4, runway5];
const checkRunway = () =>{
for(let i = 0; i < runways.length; i++){
if(runways[i].available === true){
runways[i].available = false
document.getElementById(`runway${[i]}`).style.backgroundColor = 'red'
break;
}
}
}
const landing = () =>{
if(selection.value == 'DC35'){
checkRunway();
setInterval(function(){
runways[i].available = true;
document.getElementById(`runway${[i]}`).style.backgroundColor = 'green'
}, 1000)
}
}
Your setInterval time isn't decreasing, it isn't stopping. You've never told it to stop, so what's most likely happening is that you're duplicating the setIntervals each time you call the function, meaning that multiples are running at once time. This would give you the false impression that your current click, causes a reaction, sooner. When in fact, it was a previous setInterval, executing.
If you only want it to happen once, say onclick, then use setTimeout instead.
setTimeout(function() {
runways[i].available = true;
document.getElementById(`runway${[i]}`).style.backgroundColor = 'green'
}, 1000);
Related
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
I can't figure out why setTimeout is being called multiple times in my code.
Here's a snippet of the code with what I thought was irrelevant removed:
let dead;
setup()
{
dead = false;
}
draw()
{
if(fell == true)
{
dead = true;
}
mechanics();
}
function mechanics()
{
let triggerVar;
if(dead == true)
{
triggerVar = 1;
dead = false;
}
if(triggerVar == 1)
{
setTimeout(resetG, 1500);
triggerVar = 0;
}
}
function resetG()
{
lives -= 1;
position = 0;
}
I can't tell what I'm doing wrong because whenever the character dies and setTimeout is called, it is actually not only called after the delay but also for the exact same duration after it is triggered. So in this case it is triggered first after 1500 millis and then every frame for another 1500 millis.
I managed to find the problem, which was not with the code I posted. The problem was that the constructor code that makes the object that changes dead to true if certain conditions are met was being called every frame from the moment it triggered death until the first instance of setTimeout kicked in, which means setTimeout was called every frame for 1500 milliseconds.
Chances are that you mechanics() function is called multiple times, you may give a variable to the settimeout like:
let timeoutID= setTimeout(resetG, 1500);
And in the proper place to clear it, for example after lifecycle
clearTimeout(timeoutID);
This is what my code looks like:
var fnInterval = setInterval(function() {
let b = true
if (b) {
console.log("hi")
} else {
console.log("bye")
}
b = !b
}, 1000);
clearTimeout(fnInterval, 10000)
I am a newbie to JavaScript and my aim here is to console log a message every 1 second for a total duration of 10 seconds, but during each interval I want my message to toggle its value between "hi" and "bye" . How can I do it? (as of now it displays the value for the default boolean and doesn't change later)
Move the flag variable out of the function:
let b = true;
const fnInterval = setInterval(function() {
if (b) {
console.log("hi");
} else {
console.log("bye");
}
b = !b
}, 1000);
To stop the timer after 10000 milliseconds, wrap the call to clearInterval in a setTimeout:
setTimeout(() => clearInterval(fnInterval), 10000);
Meanwhile, note that the return value of setInterval is not a function but a number, so it may be misleading to call it fnInterval.
First of all, declare let b = true outside of the callback function. It's re-initialized on each call otherwise.
Secondly, the 10000 in clearTimeout(fnInterval, 10000) isn't a valid parameter. clearTimeout(timeoutId) accepts only the first parameter and clears the timeout passed in immediately. You'd need a setTimeout to trigger this after 10 seconds, if that's your goal. But that causes a race condition between the two timeouts -- imprecision can mean you'll miss some of the logs or wind up with extra logs.
Using a counter is one solution, as other answers show, but usually when I'm using complex timing with setInterval that requires clearing it after some number of iterations, I refactor to a generic promisified sleep function based on setTimeout. This keeps the calling code much cleaner (no callbacks) and avoids messing with clearTimeout.
Instead of a boolean to flip a flag back and forth between two messages, a better solution is to use an array and modulus the current index by the messages array length. This makes it much easier to add more items to cycle through and the code is easier to understand since the state is implicit in the counter.
const sleep = ms => new Promise(res => setInterval(res, ms));
(async () => {
const messages = ["hi", "bye"];
for (let i = 0; i < 10; i++) {
console.log(messages[i%messages.length]);
await sleep(1000);
}
})();
setInterval() is stopped by clearInterval() not clearTimeout(). Details are commented in code below.
// Define a counter
let i = 0;
// Define interval function
const fnCount = setInterval(fnSwitch, 1000);
function fnSwitch() {
// Increment counter
i++;
// if counter / 2 is 0 log 'HI'
if (i % 2 === 0) {
console.log(i + ' HI');
// Otherwise log 'BYE'
} else {
console.log(i + ' BYE');
}
// If counter is 10 or greater run fnStop()
if (i >= 10) {
fnStop();
}
};
function fnStop() {
// Stop the interval function fnCount()
clearInterval(fnCount);
};
I have this a piece of js in my website to switch images but need a delay when you click the image a second time. The delay should be 1000ms. So you would click the img.jpg then the img_onclick.jpg would appear. You would then click the img_onclick.jpg image there should then be a delay of 1000ms before the img.jpg is shown again.
Here is the code:
jQuery(document).ready(function($) {
$(".toggle-container").hide();
$(".trigger").toggle(function () {
$(this).addClass("active");
$(".trigger").find('img').prop('src', 'http://localhost:8888/images/img_onclick.jpg');
}, function () {
$(this).removeClass("active");
$(".trigger").find('img').prop('src', 'http://localhost:8888/images/img.jpg');
});
$(".trigger").click(function () {
$(this).next(".toggle-container").slideToggle();
});
});
Use setTimeout():
var delayInMilliseconds = 1000; //1 second
setTimeout(function() {
//your code to be executed after 1 second
}, delayInMilliseconds);
If you want to do it without setTimeout: Refer to this question.
setTimeout(function(){
}, 500);
Place your code inside of the { }
500 = 0.5 seconds
2200 = 2.2 seconds
etc.
ES-6 Solution
Below is a sample code which uses aync/await to have an actual delay.
There are many constraints and this may not be useful, but just posting here for fun..
const delay = (delayInms) => {
return new Promise(resolve => setTimeout(resolve, delayInms));
}
const sample = async () => {
console.log('a');
console.log('waiting...')
let delayres = await delay(3000);
console.log('b');
}
sample();
you can use the promise
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
then use this method
console.log("Hello");
sleep(2000).then(() => { console.log("World!"); });
or
console.log("Hello");
await sleep(2000);
console.log("World!");
There are two (mostly used) types of timer function in javascript setTimeout and setInterval (other)
Both these methods have same signature. They take a call back function and delay time as parameter.
setTimeout executes only once after the delay whereas setInterval keeps on calling the callback function after every delay milisecs.
both these methods returns an integer identifier that can be used to clear them before the timer expires.
clearTimeout and clearInterval both these methods take an integer identifier returned from above functions setTimeout and setInterval
Example:
setTimeout
alert("before setTimeout");
setTimeout(function(){
alert("I am setTimeout");
},1000); //delay is in milliseconds
alert("after setTimeout");
If you run the the above code you will see that it alerts before setTimeout and then after setTimeout finally it alerts I am setTimeout after 1sec (1000ms)
What you can notice from the example is that the setTimeout(...) is asynchronous which means it doesn't wait for the timer to get elapsed before going to next statement i.e alert("after setTimeout");
Example:
setInterval
alert("before setInterval"); //called first
var tid = setInterval(function(){
//called 5 times each time after one second
//before getting cleared by below timeout.
alert("I am setInterval");
},1000); //delay is in milliseconds
alert("after setInterval"); //called second
setTimeout(function(){
clearInterval(tid); //clear above interval after 5 seconds
},5000);
If you run the the above code you will see that it alerts before setInterval and then after setInterval finally it alerts I am setInterval 5 times after 1sec (1000ms) because the setTimeout clear the timer after 5 seconds or else every 1 second you will get alert I am setInterval Infinitely.
How browser internally does that?
I will explain in brief.
To understand that you have to know about event queue in javascript. There is a event queue implemented in browser. Whenever an event get triggered in js, all of these events (like click etc.. ) are added to this queue. When your browser has nothing to execute it takes an event from queue and executes them one by one.
Now, when you call setTimeout or setInterval your callback get registered to an timer in browser and it gets added to the event queue after the given time expires and eventually javascript takes the event from the queue and executes it.
This happens so, because javascript engine are single threaded and they can execute only one thing at a time. So, they cannot execute other javascript and keep track of your timer. That is why these timers are registered with browser (browser are not single threaded) and it can keep track of timer and add an event in the queue after the timer expires.
same happens for setInterval only in this case the event is added to the queue again and again after the specified interval until it gets cleared or browser page refreshed.
Note
The delay parameter you pass to these functions is the minimum delay
time to execute the callback. This is because after the timer expires
the browser adds the event to the queue to be executed by the
javascript engine but the execution of the callback depends upon your
events position in the queue and as the engine is single threaded it
will execute all the events in the queue one by one.
Hence, your callback may sometime take more than the specified delay time to be called specially when your other code blocks the thread and not giving it time to process what's there in the queue.
And as I mentioned javascript is single thread. So, if you block the thread for long.
Like this code
while(true) { //infinite loop
}
Your user may get a message saying page not responding.
For sync calls you can use the method below:
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
If you need refresh, this is another posibility:
setTimeout(function () {
$("#jsSegurosProductos").jsGrid("refresh");
}, 1000);
I'll give my input because it helps me understand what im doing.
To make an auto scrolling slide show that has a 3 second wait I did the following:
var isPlaying = true;
function autoPlay(playing){
var delayTime = 3000;
var timeIncrement = 3000;
if(playing){
for(var i=0; i<6; i++){//I have 6 images
setTimeout(nextImage, delayTime);
delayTime += timeIncrement;
}
isPlaying = false;
}else{
alert("auto play off");
}
}
autoPlay(isPlaying);
Remember that when executing setTimeout() like this; it will execute all time out functions as if they where executed at the same time assuming that in setTimeout(nextImage, delayTime);delay time is a static 3000 milliseconds.
What I did to account for this was add an extra 3000 milli/s after each for loop incrementation via delayTime += timeIncrement;.
For those who care here is what my nextImage() looks like:
function nextImage(){
if(currentImg === 1){//change to img 2
for(var i=0; i<6; i++){
images[i].style.zIndex = "0";
}
images[1].style.zIndex = "1";
imgNumber.innerHTML = imageNumber_Text[1];
imgDescription.innerHTML = imgDescText[1];
currentImg = 2;
}
else if(currentImg === 2){//change to img 3
for(var i=0; i<6; i++){
images[i].style.zIndex = "0";
}
images[2].style.zIndex = "1";
imgNumber.innerHTML = imageNumber_Text[2];
imgDescription.innerHTML = imgDescText[2];
currentImg = 3;
}
else if(currentImg === 3){//change to img 4
for(var i=0; i<6; i++){
images[i].style.zIndex = "0";
}
images[3].style.zIndex = "1";
imgNumber.innerHTML = imageNumber_Text[3];
imgDescription.innerHTML = imgDescText[3];
currentImg = 4;
}
else if(currentImg === 4){//change to img 5
for(var i=0; i<6; i++){
images[i].style.zIndex = "0";
}
images[4].style.zIndex = "1";
imgNumber.innerHTML = imageNumber_Text[4];
imgDescription.innerHTML = imgDescText[4];
currentImg = 5;
}
else if(currentImg === 5){//change to img 6
for(var i=0; i<6; i++){
images[i].style.zIndex = "0";
}
images[5].style.zIndex = "1";
imgNumber.innerHTML = imageNumber_Text[5];
imgDescription.innerHTML = imgDescText[5];
currentImg = 6;
}
else if(currentImg === 6){//change to img 1
for(var i=0; i<6; i++){
images[i].style.zIndex = "0";
}
images[0].style.zIndex = "1";
imgNumber.innerHTML = imageNumber_Text[0];
imgDescription.innerHTML = imgDescText[0];
currentImg = 1;
}
}
I'm not an expert in JS domain but I've found a workaround for this problem using setTimeout() and a recursive function as follows:
i=0; //you should set i as a global variable
function recFunc() {
i++;
if (i == 1) {
//do job1
} else if (i == 2) {
//do job2
} else if (i == 3) {
//do job3
}
if (i < 3) { //we have 3 distinct jobs. so the condition is (j < 3)
setTimeout(function () {
recFunc();
}, 2000); //replace 2000 with desired delay
}
}
//
//
//
recfunc(); //start the process
const delay = (delayInms) => new Promise(resolve => setTimeout(resolve, delayInms));
await delay(100)
There is a function which sets an interval using setInterval(), but even after calling clearInterval(), I can see in the console that the else condition is still running. How can I clear that interval properly?
function increase(old, step, neu) {
var i = 0;
var delay2;
function countUp() {
if (i < 5) {
old += step;
// console.log("increase")
$("#total-price-value").text(old + " dollors");
$("#total-price-value").digits();
i++;
delay2 = setInterval(countUp, 80);
} else {
clearInterval(delay2);
console.log(delay2);
}
}
countUp();
}
It looks like you're a little confused about the difference between timeouts and intervals. Timeouts fire only once; intervals fire many times. If you're using an interval, you probably only want to set it once (you're setting it every time). If you're using a timeout, you probably want to set it every time (like you're doing).
In order to fix the problem, you'll either want to switch to timeouts (probably the easiest; just a search/replace) or only set the interval once.
For example, here is how one might use setTimeout to count up to five:
var count = 0;
function timeoutFired() {
count++;
if(count < 5) {
setTimeout(timeoutFired, 1000);
}
}
setTimeout(timeoutFired, 1000);
Using timeouts, we don't need to clear to stop it from counting; simply not setting a timeout will prevent it from running again.
Here is how one might use setInterval:
var count = 0;
function intervalFired() {
count++;
if(count >= 5) {
clearInterval(interval);
}
}
var interval = setInterval(intervalFired, 1000);
If you want some code running periodically using intervals to stop, you must call clearInterval. Note that we only call setInterval once, versus setTimeout every time we didn't want it to continue.
Apparently, you have mistaken setInterval for setTimeout. setInterval runs the enclosed function every n milliseconds while setTimeout executes only once after n milliseconds.
I suppose you wanted to "tick until 5" so here's a sample:
function increase(old, step, neu) {
var i = 0;
interval = setInterval(function() {
if (i < 5) {
//do something at this "tick"
console.log(i);
i++;
} else {
//else, stop
clearInterval(interval);
}
},80);
}
increase();