1

I have a project I'm working on, and I managed to make the shortest code to handle the problem for a certain action I want to do on a website(in this case, clicking many buttons after a certain time. This is my result so far:

if (myvar == i) {
      setTimeout(function () {
        $('.class.' + i).children('.BUTTON').click();
      }, time * i);
    } 

That would be amazing if I can use a loop for it, since as you can notice there are many classes in there with the same name,and I'm using setTimeout to slow down the process so the site can understand I'm "clicking" it's buttons. So, for now, the many if with numbers instead of the "i" works good, but I know out there there is a better way, problem is if I implement any kind of loop the script breaks ;( suggestions?

TweakFix
  • 31
  • 2
  • The other codes has >= i to be clear, that is the last one so it doesn't searches for inexistant buttons. – TweakFix May 15 '16 at 15:04
  • "since as you can notice there are many classes in there with the same name" ... you're not posting any html or link to example, so how can we notice? Read [mcve] – yezzz May 15 '16 at 15:18

1 Answers1

2

If I'm guessing correctly then this is what you've probably tried:

for (var i = 0; i < 100; i++) {

    setTimeout(function() {

        $('.class.' + i).children('.BUTTON').click();

    }, time * i);

}

It didn't work because of the asynchronous nature of javascript due to which the callback of setTimeout doesn't get executed immediately. This is good for your purpose, BUT every time you call setTimeout, its callback is actually referring to the same iterator i (due to lexical-scoping).

So that when the callbacks are actually executed, each callback now refers to the same i (with the same value) and, therefore, all the buttons get clicked simultaneously.

This problem can also be attributed to the preference of lexical-scoping over block-scoping in javascript. However, we know that a function in javascript also behaves as a block-scoped construct (in fact it is the only thing in javascript that is block-scoped). So we will use it like this:

for (var i = 0; i < 100; i++) {

    (function(i) { // IIFE starts

        setTimeout(function() {

            $('.class.' + i).children('.BUTTON').click();

        }, time * i);

    })(i); // <-------IIFE ends

}

What I did here is called an IIFE (Immediately Invoked Function Expression). An IIFE is a function-expression that gets executed immediately when the program control reaches it. And because a function is block-scoped in javascript, the variable i that is passed to it becomes a member of it's scope (due to pass-by-value) and thus no longer depends on the outer loop's i.

So basically we've created a new i within the IIFE. And for each IIFE the value of i is different.


Here's a simple example:

WITH IIFE:

for (var i = 0; i < 100; i++) {

    (function(i) { // IIFE starts

        setTimeout(function() {

           console.log(i); // <----- simply printing the iterator i

        }, 500);

    })(i); // <-------IIFE ends

}

OUTPUT:

0
1
2
3
... (upto 99)

WITHOUT IIFE:

for (var i = 0; i < 100; i++) {

        setTimeout(function() {

           console.log(i); // <----- simply printing the iterator i

        }, 500);

}

OUTPUT:

100
100
100
... (100 times)
Community
  • 1
  • 1
Soubhik Mondal
  • 2,666
  • 1
  • 13
  • 19