Javascript while setTimeout [duplicate] - javascript

This question already has answers here:
How do I add a delay in a JavaScript loop?
(32 answers)
Closed 6 years ago.
I want to make a GreaseMonkey script. I want to have a setTimeout at the end of my while, but I don't know how to do that.
run();
function run(){
var klovas = document.getElementById("light").innerHTML;
var btn = document.getElementsByClassName("farm_icon farm_icon_a");
if(klovas < 6){
alert("Kevés egység van");
} else {
var i = 0;
while (i < btn.length){
if(typeof btn[i] != "undefined"){
btn[i].click();
}
i++;
setTimeout("run()", 3000);
}
}
}
With this code, the problem is that the setTimeout is not working and doesn't wait 3 seconds like it is supposed to.
I tried other ways, but nothing has worked.
EDIT
function run(){
var klovas = document.getElementById("light").innerHTML;
var btn = document.getElementsByClassName("farm_icon farm_icon_a");
if(klovas < 2){
alert("Kevés egység van");
} else {
var i = 0;
while (i < btn.length){
if(typeof btn[i] != "undefined"){
btn[i].click();
}
i++;
}
}
}
setInterval(run, 6000);
I tryed this. Its runing every 6 sec, but i get error in website, that i cand click more than 5 times in a sec. So waiting 6secound when i open the page, and after click, and i get error. Its not jet working. :(

If you wanted it to only trigger once:
function run(){
var data = [1,2,3];
var i = 0;
while (i < data.length) {
console.log(data[i]);
i++;
}
}
setTimeout(run, 3000);
The way you wrote it now, it would repeat every 3 seconds.
function run(){
var data = [1,2,3];
var i = 0;
while (i < data.length) {
console.log(data[i]);
i++;
}
setTimeout(run, 3000);
}
run();
But setInterval would accomplish the same results.
function run(){
var data = [1,2,3];
var i = 0;
while (i < data.length) {
console.log(data[i]);
i++;
}
}
setInterval(run, 3000);
EDIT
User wanted to see what would happen if you call setInterval from inside the callback function. Note that the number of intervals grows exponentially every 3 seconds.
setInterval causes the function to run every 3 seconds, while setTimeout causes the function to run once in 3 seconds.
var numberOfIntervals = 0;
function run(){
setInterval(run, 3000);
numberOfIntervals++;
console.log(numberOfIntervals);
}
run();

There are a few problems here.
Firstly, while setTimeout can accept a function as its first argument, you would want to pass the function as an argument, not execute the function, so you should replace "run()" with run.
Secondly, I'm not exactly sure why you're recursing -- why is setTimeout inside run()? Instead of putting it inside your run function, try putting it at the bottom, and deleting the run() call at the top. As far as I can tell, there's no reason that this code needs to recurse at alll.

Related

How to use the setTimeout to delay the increment counter in the loop? [duplicate]

This question already has answers here:
How do I add a delay in a JavaScript loop?
(32 answers)
Closed 4 years ago.
I want to use setTimeout to delay the increment counter in the loop in order to change picture every secs. I try to delay the updatePic() use setTimeout but it doesn't work either.
Please help. Thanks.
My JS code:
function picAnimation() {
//var pic = document.getElementById('pic').src;
for(i = 2; i < 25; ) {
updatePic(i);
setTimeout(function() {increment(i);} , 1000);
}
}
function updatePic(i) {
if(i > 9) {
document.getElementById('pic').src = "./animation/0" + i + ".png";
} else {
document.getElementById('pic').src = "./animation/00" + i + ".png";
}
}
function increment(i) {
i++;
}
picAnimation();
My html code:
<center><img id = "pic" src="./animation/001.png" alt="N/A" width="800" height="300"></center>
A for loop is not the right statement to use in this case. The loop does not wait for setTimeout to finish, calling updateLoop and setTimeout 23 times almost instantly. setTimeout is a function that calls the function in the first argument, after a set amount of milliseconds.
Also, the increment function does not change the value of i; JS copies the data, increments the copy, then discards it. Something like that is possible in C++, but not in JS.
You should instead use setTimeout to call picAnimation.
function picAnimation(i) {
updatePic(i);
if (i < 25)
setTimeout(function() {picAnimation(i + 1)}, 1000);
}
picAnimation(2);
I'd use recursion -- not a for-loop.
function doSomething (counter) {
// Terminal case
if (counter === 25) {
return;
}
// Do work here
// Schedule the next.
setTimeout(doSomething, delay, ++counter)
}
// Then start the process
doSomething(0);
You could write a general-purpose function, then your updater becomes just another use-case.
function loopUntilFalse (delay, fn) {
if (fn() !== false) setTimeout(loopUntilFalse, delay, delay, fn);
}
var animated = 0;
function picAnimation() {
if (animated >= 25) return false;
updatePic(animated);
animated++;
}
picAnimation();

Cancel an infinite loop in JavaScript

I am trying to timeout a function in case it has an infinite loop. But the below does not work. Any idea why and how to fix it?
setTimeout(clearValues,1000);
function clearValues(){
i=0;
alert("hi "+i);
}
i=19
function infin(){
while(i>0){
console.log(i);
i++;
}
alert("Done");
}
infin();
In the below case, I get the alert displayed ( a bit later than expected ) and the console statements continue printing even after the alert. That means setTimeout did not wait for the loop to end in this case. Any explanation for this?
setTimeout(clearValues,500);
function clearValues(){
alert("clear");
}
function infin(){
for(i=0;i<10000;){
i=i+0.3;
console.log(i);
}
}
infin();
setTimeout works asynchronously, means it will run after 1000ms and the previous event loop is completed. Since the while loop will never be completed, the callback will never be called.
Add a condition to the loop if you want to exit it.
Another solution might be to use interval:
var code = function(){
console.log('tick');
};
var clock = setInterval(code, 200);
When you don't need it anymore:
clearInterval(clock);
It works, when you made the infin call with a slightly different change.
var i = 0;
setTimeout(clearValues, 1000);
var interval = setInterval(infin, 0);
function clearValues() {
out("clear");
clearInterval(interval);
}
function infin() {
if (i < 10000) { // if you be shure that you
i++;
out(i);
} else { // never reach the limit,
clearInterval(interval); // you can remove the four
} // commented lines
}
function out(s, pre) {
var descriptionNode = document.createElement('div');
if (pre) {
var preNode = document.createElement('pre');
preNode.innerHTML = s + '<br>';
descriptionNode.appendChild(preNode);
} else {
descriptionNode.innerHTML = s + '<br>';
}
document.getElementById('out').appendChild(descriptionNode);
}
<div id="out"></div>

setInterval within a for-loop not working

What I want is an infinite loop that alerts 1, 2, 3, 1, 2, 3, ... with an interval of 2000 milliseconds. But it's not working. The console's not showing any error though. What's the problem here?
for (i = 1; i <= 3; i++) {
setInterval(function() {
alert(i);
}, 2000);
if (i == 3) {
i = 0;
}
}
This will do:
var i = 0;
setInterval(function () {
i += 1;
if (i == 4) {
i = 1;
}
alert(i);
}, 2000);
I've checked it chrome too.
It outputs 1,2,3,1,2,3... as you have requested.
you can not setInterval() inside a for loop because it will create multiple timer instance.
The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds).
The setInterval() method will continue calling the function until clearInterval() is called, or the window is closed.
The ID value returned by setInterval() is used as the parameter for the clearInterval() method.
Tip: To execute a function only once, after a specified number of milliseconds, use the setTimeout() method.
var i = 0
function test() {
i = i % 3;
++i;
alert(i);
};
setInterval('test()', 2000);
You would not need a loop for this, an interval already goes on infinitley. Try this instead:
var i = 1;
setInterval(function() {
alert(i);
i++;
if(i > 3) {
i = 1;
}
}, 2000);
The reason why this is not working is because you enter the infinite loop in a blocking state, meaning that the interval is never entered as the browser is busy looping. Imagine the browser can only do one thing at a time, as in a single thread, so the loop is it, and cannot do anything else until it's done, and in your case it never is, therefore the interval is waiting for it's turn, which it never gets.
You could make it none blocking like this:
function recursion () {
for (var i = 1; i < 4; i++) {
var num = i;
setInterval(function() {
console.log(String(this));
}.bind(num), 2000);
}
recursion ();
}
recursion ();
my best suggestion is . use event monogramming righterthen loop ,
first make a function then after completing of setInterval call to next function and so on.. that's how u can solve this p

How to set time delay in javascript

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)

jQuery Promise with setTimeout

I need one setInterval to start after another setInterval ends. Is there a way to do this with promises?
Ideally, I would like the code to look something like this:
for (i=0; i<5; i++){
setInterval(fun_1, 1000)
//wait until this is done
}
The setInterval calls the provided function after given interval of time until you clear its object. So you do not need a loop for this. You can use a counter to terminate it after counter reaches desired value.
Live Demo.
var myInter;
i = 1;
function fun_1()
{
// some code
if(i++==5)
clearInterval(myInter);
}
myInter = setInterval(fun_1, 1000);
Do you mean that you would like the second interval to begin the countdown after the previous interval is done? In that case, you would say
window.setTimeout(fun_1, 1000);
function fun_1
{
window.setTimeout(fun_2, 1000);
}
This starts the countdown for the second timeout after the first one has completed.
You should call the next interval after the first one completes
var cnt = 0;
function executeNextStep(){
fun_1();
if (cnt<5) {
window.setTimeout(executeNextStep,1000);
}
cnt++;
}
executeNextStep(); //execute this right away
//window.setTimeout(executeNextStep,1000); use this if you want it to be delayed
if you need to execute different functions:
function fun_1() {
console.log(1);
}
function fun_2() {
console.log(2);
}
function fun_3() {
console.log(3);
}
var fnc_stack = [fun_1, fun_2, fun_3];
var cnt = 0;
function executeNextStep(){
fnc_stack[cnt]();
cnt++;
if (cnt<fnc_stack.length) {
window.setTimeout(executeNextStep,1000);
}
}
executeNextStep();

Categories