开发者

why does this setTimeout() call work in the console but not as a greasemonkey script?

开发者 https://www.devze.com 2023-04-03 21:06 出处:网络
When I use a setTimeout() in a for() loop in a greasemonkey script, it doesn\'t appear to work at all.However, the exact same code works fine if I run it in the Firebug console.Here\'s the code:

When I use a setTimeout() in a for() loop in a greasemonkey script, it doesn't appear to work at all. However, the exact same code works fine if I run it in the Firebug console. Here's the code:

// ==UserScript==
// @name           setTimeout test
// @include        *
// @run-at         document-end
// ==/UserScript=


function test(delaytime) {
    alert("test called with "+delaytime);
}

function test2() {
  for( var i = 0; i < 100; i+= 10 ) {
    setTimeout('test('+i+');', i);
  }
}

setTimeout(test2,10);

If I replace the for() loop with explicit calls like the following, then it works fine.

setTimeout(function() { test( 0); },  0);
setTimeout(function() { test(10); }, 10);
setTimeout(function() { test(20); }, 20);
setTimeout(function() { test(30); }, 30);
setTimeout(function() { test(40); }, 40);开发者_开发问答
setTimeout(function() { test(50); }, 50);
setTimeout(function() { test(60); }, 60);
setTimeout(function() { test(70); }, 70);
setTimeout(function() { test(80); }, 80);
setTimeout(function() { test(90); }, 90);

What's the difference? Is there any way I can get the for loop generated setTimeouts to work in greasemonkey?


Because when the string is evaled at the time the setTimeout fires in order to execute the function, the loop has run it's course and i is sitting at the last value of the loop.

To freeze the value of i for each call to setTimeout, you need to capture it in a function closure like this:

function test2() {
  for( var i = 0; i < 100; i+= 10 ) {
    setTimeout(function(val) {
        return(function() {test(val);});
    } (i), i);
  }
}

This also has the advantage of getting rid of the eval in the setTimeout parameter.


You have to duplicate the value of i into a locally scoped variable:

function test2() {
  for( var i = 0; i < 100; i+= 10 ) {
    (function(i){
        setTimeout('test('+i+');', i);
    })(i);
  }
}

On a side note: You should pass an anonymous function to setTimeout instead of passing it a string (which will be eval'ed). It's much faster this way:

function test2() {
    for( var i = 0; i < 100; i+= 10 ) {
        (function(i){
            setTimeout(function(){
                test(i);
            }, i);
        })(i);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消