Javascript For-Loop issue


I'm trying to click every item with a 200 millisecond interval, I wrote the following script however there seems to be an issue with the For Loop. Some one please tell me what you think is wrong with it.

function clickLink(elm) {
    var evt = document.createEvent('MouseEvents');
    evt.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    elm.dispatchEvent(evt);
}

function sel() {
    elms = document.getElementsByClassName('uItem');
    var inputs= elms;
    var howbig= elms.length;
    console.log(howbig);

    for (var i=250;i<elms.length;i++)
    {
        setTimeout(clickLink(inputs[i]),200)
    };

There's 1400 uItem 's on the page.

The way your doing this won't get you one click per 200ms, you will register all your clicks almost at the same time(the time a loop last to iterate 1000 items,almost instantly) so you basically would get your 1000+ aprox. click events fired almost simultaneously, I think that could cause issues, so to make sure they are executed once in a 200ms approx. do this:

window.i=250;
for (var i=250;i<elms.length;i++)
{
setTimeout(function() {
   clickLink(inputs[window.i]);
   window.i++;
},200 * (i-249)); //Here we make sure events are spaciated 200ms each approx.
};

UPDATE: Updated the anonymouse function to pass i to avoid closure issue noted in comments.

UPDATE 2: Added window.i inside anonymous function to workaround i scope issue

UPDATE 3: Updated my code above to fix the interval at which each click event is fired, we were using 200 * i but that is only correct if i starts at zero, here it starts at 250 so the correct form is 200 * (i-249)

In spite of some comments, the i scope issue it's resolved using window.i , see test here https://tinker.io/98fd4/1


Cleanest solution is just to have your clickLink function return a function.

function clickLink(elm) {
    return function() {
        var evt = document.createEvent('MouseEvents');
        evt.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        elm.dispatchEvent(evt);
    };
}

Then stagger the timers if you want an interval:

var start = 250
for (var i=start;i<elms.length;i++) {
    setTimeout(clickLink(elms[i]), 200 * (i - start))
}

Or ditch the loop, and use setInterval:

var i = 250,
    len = inputs.length;
var itvl = setInterval(function() {
    clickLink(elms[i++]);
    if (i >= len)
        clearInterval(itvl);
}, 200);

And to back to your original clickLink function


There is a issue of the scope of ì, the delay which needs to be incremented accordingly with i to have a 200 ms interval and the fact that setTimeout expects a function as is argument.

    for (var i=250;i<elms.length;i++)
    {
        setTimeout((function() {
            var j = i // keep i as j in this closure
            return function() { // return the right function
                clickLink(inputs[j])
            }
        })(),200 * i) // set the delay depending on i
    };

function sel() {
  var elems = document.getElementsByClassName('uItem');
  for (var i = 0; i < elems.length; i += 1) {
    setTimeout(function (el) {
      return function () {
        clickLink(el);
      };
    }(elems[i]), i * 1000);   
  };
}

demo: http://jsfiddle.net/4hYWy/


little note: I don't like these constructs (calculating the delay like in the example). But it is very close to the original code, and my solution of choice would have probably made it too complicated.


The easiest way, if you're using a moderately-recent version of JavaScript, is to use bind. This creates a single function object with arguments bound to it that are calculated when bind is called, not later. The line you want is thus:

setTimeout( clickLink.bind( null, inputs[i] ),  /* delay expression here */ )

You can make bound functions explicitly, but it's ugly and you should only do it if you have a strong requirement to support old JavaScript interpreters.


This code wait 200ms, execute a callback and prepare a new callback executed 200ms later. The second callback is executed 400ms after the call of sel and so on.

    var callback = function(i) {
        return function() {
            if (i < elms.length) {
                clickLink(inputs[i]);
                setTimeout(callback(i + 1), 200);
            }
        };
    };
    setTimeout(callback(250), 200);

No scope issues or calculating correct interval.

function sel() {
    var elms = document.getElementsByClassName('uItem'),
        i = -1,
        I = elms.length,

        rec = function () {
            if ( i++ < I ) {
                clickLinks(elms[i]);
                setTimeout(rec, 200);
            }
        };

    rec();
}

http://jsfiddle.net/joplomacedo/cqfxH/