I seen this loop , and I don't understand how after the second loop ( when I = 2 ) the timeout is still 4 second and not 7 seconds.
First loop , i = 0 , x = 0 , and the output is 0 after 1 sec - i understand why
Second loop , i = 1 , x = 1 , and the output is 1 after 4 sec - i understand why 3000 X 1 + 1000 = 4000 ( 4 sec )
Third loop , i = 2 , x = 2 , the output is 2 after 4 sec - why 4 sec and not 7 ? 3000 X 2 + 1000 is 7000 ( 7 sec ) but why i get the output after 4 sec and not 7 ?
for (var i = 0; i <= 10; i++) {
(function(x) {
setTimeout(function() {
console.log(x);
}, 1000 + (3000 * x));
})(i);
}
The current execution plan is as follows:
As you can see, all the executions were relative to the starting point (almost).
If you wanted the executions to happen one after the other (0 after 1 second, 1 after 5 seconds, 2 after 12 seconds), then do this:
function compoundedInterval(x, limit) {
if (x > limit) {
return;
}
setTimeout(function() {
console.log(new Date(), x);
compoundedInterval(x + 1);
}, 1000 + (3000 * x));
}
compoundedInterval(0, 10);
I've updated the console.log to add the time so we can see the actual gaps between executions.
I now have the ff. results:
The timeout for i, x = 2 is 7 seconds. That is why it happens 3 seconds after i, x = 1 fires. This function as written does not register the next timer when the previous timer fires, it registers all 10 within a few milliseconds of being called, They go off at 4, 7, 10, 13, 16, 19, 22, 25, 28, and 31 seconds.
This one, however, will have a longer delay between each one. The key is registering the next timer as the current one is firing instead of all 10 at once.
function timeRecurse (i=0) {
var next = () => timeRecurse(i +1)
console.log(i);
return (i < 10) ? setTimeout(next, 1000 + (3000 * i)): null;
}
timeRecurse();
There is 7 seconds delay for third iteration, but from start of the script, not from second iteration. It is because of asynchronous nature of javascript.
All timeouts will start at the same time and each console output will happen 3 seconds after previous one.
Check javascript event loop for more information.
For example, this video pretty nicely explains that topic in my opinion.
Related
Considering this code:
var x = 3;
var i = 0;
while (i < 3) {
x += 1;
i += 1;
}
println(x);
Why would the output be 6? Can someone break it down for me?
I understand that x will continue adding 1 to it's value, but why does the i<3 limit it to 6?
The answer will be 6 because your initial value of X is 3.
You have only 3 iterations in your while loop.
i = 0 => x +1 = 4
i = 1 => x + 1 = 5
i = 2 => x + 1 = 6
i = 3 => exit loop
I will explain it step by step
while loop will take values, while i is smaller than 3 right.
X starts as 3 and i starts as 0.
While checks if i < 3. (it is 0 for now )
(x+=1 means x = x + 1 (same for i ))
i was 0, so while loop will start working.
x will become 4 and i will become 1.
second run: i is 1 still lower than 3 so while loop will keep working.
x will become 5 and i will become 2
i is still lower than 3 so while loop will keep working
x will become 6 and i will become 3
now i is equal to 3 so no longer lower than 3. While loop will stop working and you will get the outputs.
But if console.log (x) was in the while loop. You will get all the x results.
The output would be:
4
5
6
So, if your question is why am I getting only 6 as an output? It is because your function comes after the while loop.
Before entering into the loop: x=3, i=0 (i is less than 3, so the condition is true)
After the first step: x=4, i=1 (i is less than 3, so the condition is true)
After the second step: x=5, i=2 (i is less than 3, so the condition is true)
After the third step: x=6, i=3 (i is not less than 3, so the condition is false)
Because the condition is false, it is exited from the loop and the value of x is printed in the output.
Also, println() is not defined in JavaScript. We can use console.log().
The code of
var x = 3;
var i = 0;
while (i < 3) {
x += 1;
i += 1;
}
increments x and i repeatedly. Initially, i is 0, which is important, as its incrementation's result determines whether the loop should continue. Since the loop criteria is that i < 3 is (still) true, starting from 0 and adding 1 to the value of i, your loop's block will be executed 3 times (it's executed for i=0, then it's executed for i=1 and then it's executed for i=2 and finally, for i=3 it's not executed, because the condition of i < 3 is no longer true when i=3).
Since the loop block is executed 3 times and both i and x is incremented by 1 at each execution, their value increases by the same value during the process. Since i was increased by 1 a total of three times, its value was changed from 0 to 3 (0 + 1 + 1 + 1 = 3). Since the initial value of x was 3, it changed from 3 to 6 (3 + 1 + 1 + 1 = 6).
const secondsInterval = () => {
const date = getNow();
if (dayjs(date).minute() % 5 !== 0 && dayjs(date).second() !== 0) {
console.log("return...");
return;
}
console.log("checking...");
...
};
// Check every second, if we're at the 5-minute interval check.
setInterval(secondsInterval, 1000);
This seems to get stuck. It's "checking" on every second of each 5 minute mark. What am I doing wrong? Thanks in advance.
Goal: To "check" every minute and 00 seconds: :00:00, :05:00, :10:00, , :15:00, etc Thanks again.
You should find out what's the time to your next rounded 5 min. like this:
const FIVE_MIN = 1000 * 60 * 5;
function waitAndDoSomething() {
const msToNextRounded5Min = FIVE_MIN - (Date.now() % FIVE_MIN);
console.log(`Waiting ${msToNextRounded5Min}ms. to next rounded 5Min.`);
setTimeout(() => {
console.log('It is now rounded 5 min');
waitAndDoSomething();
}, msToNextRounded5Min);
}
waitAndDoSomething();
If all you care about is executing some code every 5 mins, then don't have it execute every second needlessly, only to return out. Just have it run every 5 mins (300000 MS) and have it do what you need to do and remove all the checking for 5 minute mark code out its unnecessary.
const secondsInterval = () => {
// -------------------- Remove ----------------
//const date = getNow();
//if (dayjs(date).minute() % 5 !== 0 && dayjs(date).second() !== 0) {
// console.log("return...");
// return;
//}
// -------------------- Remove ----------------
console.log("checking...");
...
};
// Check every 5 mins
setInterval(secondsInterval, 300000);
Your logic for the if is screwy. Here I reversed it so the if takes care of "do the thing" and the else returns.
const secondsInterval = () => {
const date = dayjs(new Date());
if (dayjs(date).minute() % 5 == 0 && dayjs(date).second() == 0) {
console.log("checking...");
} else {
console.log("returning...");
return;
}
//...
};
// Check every second, if we're at the 5-minute interval check.
setInterval(secondsInterval, 1000);
<script src="https://unpkg.com/dayjs#1.8.21/dayjs.min.js"></script>
I found this script from a website. The loop ends when it has followed 40 Instagram accounts at a 2-second interval. How do I modify the script so it waits for 10 minutes before repeating the same loop for 3 times? Basically, it goes:
Follow an account and wait for 2 seconds X40
Wait for 10 minutes
Follow an account and wait for 2 seconds X40
Wait for 10 minutes
Follow an account and wait for two seconds X40
Wait for 10 minutes
---LOOP ENDS---
var TagFollow = document.getElementsByTagName("button");
var SearchFollow = "Follow";
var foundFollow;
function clickfollow(){
for (var i = 0; i < TagFollow.length; i++) {
if (TagFollow[i].textContent == SearchFollow) {
foundFollow = TagFollow[i];
foundFollow.click();
break;
}
}
}
var i = 1;
function myLoop() {
setTimeout(function() {
console.log(new Date().toLocaleTimeString());
clickfollow();
//document.getElementsByTagName("ul")[3].scrollIntoView(false
i++;
if (i < 41) {
myLoop();
}
}, 2000)
}
myLoop();
Thanks in advance!
You do not need nested loops. You can "linearize" them in single loop (I do not recall the correct therm now). So basically you want loop of 3 * 40 = 120 and after each 40 you need to use increased delay of 10 * 60 * 1000 = 600000. You help yourself by using modulo function i%40. Because you start with 1, the each 40th iteration is when remainder of i divided with 40 is zero.
So basically change if (i < 41) to if (i < 121) and }, 2000) to }, i%40 === 0 ? 600000 : 2000)
I'm creating a countdown, which i need to count down it to 0 but in random numbers.
Ex- countdown from 4 minutes by second by second, but i need to show a value between 300 to 390 countdown to 0 with random numbers within above 4 minutes period.
I created random number count down, but still cannot able to figure out how to target that become 0 within given time.
<script>
var count = 350; //this is a random value between(300-390)
var timer = setInterval(function() {
//this will generate number between 0 to 10 and reduce it from count randimly
count -= Math.floor(Math.random()*9);
//set it to html element
jQuery('#maindvpart').html(count);
//when number become 0
if( count <= 0) {
jQuery('#maindvpart').html(0);
count = 0;
clearInterval(timer);
}
//but i need to run this countdown within 4 minutes
//(so when 0 minutes ends above count should zero, until 0 it should count down from random number)
},1000);
</script>
<div id="maindvpart"> </div>
anyone have idea or example how to do this, thank you
Your "timer" runs each second. When you do "count -= Math.floor(Math.random()*9);", it reduces "count" variable value much faster, so you will always reach "count <= 0" much faster than 4 minutes. If you want to run your timer for 4 minutes, you need to run your timer per second - 240 times, and "display a random number", but do not subtract that random number from count. Does this help?
Editing with an example, hoping it would point you towards your goal:
<script>
var count = 240; //4 minutes
var displayNumber = 350; //or whatever number you want to start with
var timer = setInterval(function() {
//this will generate number between 0 to 10 and reduce it from displayNumber randomly
displayNumber -= Math.floor(Math.random()*9);
count--;
console.log(displayNumber);
// exit if either the display number is <= 0 or the time is up
if( displayNumber <= 0 || count <= 0) {
console.log(0);
displayNumber = 0;
clearInterval(timer);
}
},1000);
</script>
Solution 1:
simply modify the time interval after which the random number is reduced by unit step (ie:1) to indicate the time step necessary for the random number to equal 0 when the time is up . the equation would be :
{delay before subtracting 1 from rand# (in sec) = time elapsed till rand# reaches 0 (in sec)/rand#}
ex:
1) rand# = 300 , needed to count down till reaches 0 in 2 minutes (120sec) , then 300 needs to count down by 1 each 120/300 sec
var count = 300 // your randomly generated number;
var time = 60 //time elapsed before the random number to equal 0;
var timer = setInterval(function() {
count = count -1;
console.log(count);
if( count <= 0) {
count = 0;
clearInterval(timer);
}
},(time/count)*1000);
Solution 2:
modify the unit step by which the random number is decreased every second till it reaches 0 after the specified time is elapsed . the equation would be :
{random # decrement step = rand#/time elapsed till rand# reaches 0 (in sec)}
ex:
1) rand# = 300 , needed to count down till reaches 0 in 1 minute (60sec) , then 300 needs to count down by 300/60 each 1 sec
var count = 300 // your randomly generated number;
var time = 20 //time elapsed before the random number to equal 0;
var decrementStep=count/time;
var timer = setInterval(function() {
count = count - decrementStep;
console.log(count);
if( count <= 0) {
count = 0;
clearInterval(timer);
}
},1000);
Please take a look at my code below, I don't know why it produce expected output. I think the way I used setInterval() and setTimeout is wrong. Somehow the process doesn't go by 1 order from top to bottom. It seems like there are 3 threads run in parallel. How can I fix it? Thank you.
(function() {
var nums = [1, 2, 3];
nums.forEach(
(e) => {
console.log(e);
var frame = 0;
let loop = setInterval(function() {
if (frame === 3)
clearInterval(loop);
console.log(e + " frame " + frame);
frame++;
}, 1000);
let wait = setTimeout(function() {
console.log(e + " 2 second passed");
}, 2000);
}
)
})();
Expected output:
1
1 frame 0
1 frame 1
1 frame 2
1 2 seconds passed
2
2 frame 0
2 frame 1
2 frame 2
2 2 seconds passed
3
3 frame 0
3 frame 1
3 frame 2
3 2 seconds passed
Actual output:
1
2
3
1 frame 0
2 frame 0
3 frame 0
1 frame 1
1 2 second passed
2 frame 1
2 2 second passed
3 frame 1
3 2 second passed
1 frame 2
2 frame 2
3 frame 2
1 frame 3
2 frame 3
3 frame 3
Because Javascript is asynchronous, you need some way of waiting for each of the intervals and the timeout to complete before running the next.
One way of doing this is by using async/await and wrapping the intervals and timeout in a promise.
(async function() {
var nums = [1, 2, 3];
for (const e of nums) {
console.log(e);
let frame = 0;
await new Promise(resolve => {
let loop = setInterval(function() {
if (frame === 3) {
clearInterval(loop);
resolve();
} else {
console.log(e + " frame " + frame);
frame++;
}
}, 100);
})
await new Promise(resolve => {
let wait = setTimeout(function() {
console.log(e + " 2 second passed");
resolve();
}, 200);
})
}
})();
No idea what you going to accomplished with this code. but please try with below approach. you can console log what you asked. Do changes as your favor,
let nums = [1, 2, 3];
const timesecs = 1000;
const timeOut = (num) => {
setTimeout(
() => {
console.log(num);
nums.forEach(
(item, index) => {
console.log(num + " frame " + index);
}
)
//console.log(`${num} ${num+1} seconds passed`);
console.log(`${num} 2 seconds passed`);
},
num * timesecs
)
}
nums.forEach((num) => {
timeOut(num);
});
Javascript doesn't work this way. You need to understand the concept of ASYNC operations and callbacks first. Aysnc operations, like setTimeout and setInterval, do not wait for their callback functions to finish before moving to the next line of the code. They just move the execution cursor to the next line. Your setInterval function will finish its callback execution after 1000 milliseconds.
There are new functionalities are added like await and async function. You may want to look into them to achieve what you want.
The for loop you are running should be inside the interval rather than what you are doing.
(function () {
var nums = [1, 2, 3];
var ind = 0;
let loop = setInterval(function(){
if(ind === 2){
clearInterval(loop);
}
console.log(nums[ind]);
nums.forEach(e => {
console.log(nums[ind] + " frame " + e);
});
console.log(nums[ind] + " 2 seconds passed");
ind++;
}, 2000);
})();
You have a forEach loop that will loop 3 times. On the first iteration, it will:
console.log the frame (1)
create an interval that will execute in 1 second
create a timeout that will execute in 2 seconds
Then the second iteration of the loop happens immediately after the first iteration so it will again:
console.log the frame (2)
create another new second interval that will execute in 1 second
create another new second timeout that will execute in 2 seconds
Finally the third iteration will occur, immediately and it will:
console.log the frame (3)
create another third new interval that will execute in 1 second
create another third new timeout that will execute in 2 seconds
Next, all three of your newly created intervals will execute about 1 second after the loop finishes. Each interval will execute very slightly behind the previous interval. And each one contains a "closure" around the variable frame (i.e. when they were created, they all "captured" frame when it was set to 0 so they all console.log(0).
On the next second, each of the 3 intervals will attempt to run again (now each with frame === 1), and the 3 timeouts will also attempt to run. Note that each timeout also has formed a "closure", locking in the value of e at the time it was created. You end up getting a bit of staggering of intervals executing, mixed with timeouts executing.
The 3 timeouts only ever happen once each.
The remainder of the output is the set of 3 intervals successively executing, with a 2 second gap between each set.
You could achieve your output by just using one interval (with no loop), set to fire every second and print something. I'm not sure of the requirements regarding how many seconds apart you need these statements to be printed, so I cannot produce the exact code that you need but here's something that produces your desired output with my best guess at the timing:
var num = 1;
var frame = 0;
var loop = setInterval( function() {
if (frame === 0) {
console.log(num);
}
if (frame >= 0 && frame <= 2) {
console.log(num + " frame " + frame);
}
if (frame === 4) {
console.log(num + " 2 seconds passed");
num++;
frame = -1;
}
if (num > 3) {
clearInterval(loop);
}
frame++;
}, 1000);