问题
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?
回答1:
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.
回答2:
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);
}
}
来源:https://stackoverflow.com/questions/7356976/why-does-this-settimeout-call-work-in-the-console-but-not-as-a-greasemonkey-sc