-
-
Save shiffman/7b96d9951bb3865e7d38 to your computer and use it in GitHub Desktop.
// While this seems like the right idea | |
// This does not work at all! | |
// The loop will finish and i will be at 10 by | |
// the time the anonymous function is called | |
for (var i = 0; i < 100; i++) { | |
setTimeout(function() { | |
console.log(i); | |
}, 100*i); | |
} |
// Thanks to Sam Lavigne for suggesting this nice-looking methodology | |
for (var i = 0; i < 10; i++) { | |
// This will work by passing in a variable | |
// to a separate function | |
countit(i); | |
} | |
function countit(num) { | |
// This is a closure where | |
// the function declared here will retain | |
// num even after this has been completed | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures | |
setTimeout(function() { | |
console.log(s + num); | |
}, num * 1000); | |
} | |
// Option #2 | |
// Function factory | |
function count(val) { | |
return function() { | |
console.log(val); | |
} | |
} | |
for(var i = 0; i < 100; i++) { | |
setTimeout(count(i), i*100); | |
} |
// Option #3 | |
// This is basically the same thing but using bind() | |
function count(val) { | |
console.log(val); | |
} | |
for(var i = 0; i < 100; i++) { | |
setTimeout(count.bind(null, i), i*100); | |
} |
// Option #4 | |
// Same as #2, but anonymous self-executing | |
function count(val) { | |
console.log(val); | |
} | |
for(var i = 0; i < 100; i++) { | |
setTimeout(function(val) { | |
return function() { | |
console.log(val); | |
} | |
}(i), i*100); | |
} |
// Thanks to Sam Lavigne for suggesting this nice-looking methodology | |
for (var i = 0; i < 10; i++) { | |
// This will work by passing in a variable | |
// to a separate function | |
countit(i); | |
} | |
function countit(num) { | |
// This is a closure where | |
// the function declared here will retain | |
// num even after this has been completed | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures | |
setTimeout(count, num * 1000); | |
function count() { | |
console.log(num); | |
} | |
} |
I think this might be the nicest option:
function count(val, t) {
setTimeout(function(){
console.log(val);
}, t);
}
for(var i = 0; i < 100; i++) {
count(i, i*100);
}
Option #2. As it turns out, you are not 'creating a new function inside the loop.' You are doing the opposite, by using a function that returns a function. All done outside the loop. This is a good thing!
Related - are you using JSHint? It would have caught that #1 and #4 are bad.
@antiboredom wow, i'm not sure how I missed thinking of it that way! @desandro @NV thanks for the thoughts!
Making a note here of this suggestion https://github.com/caolan/async/blob/master/README.md#eachSeries
I agree with @desandro that you want the to name and define the function outside the loop to avoid creating multiple copies of the function (as #4 would do). @antiboredom your version is easy on the eyes, and makes it clear that we want to form a closure over i
each time count
is called in the loop.
In ES6 there will be a let
keyword, allowing you to express this idea even more elegantly:
for(var i = 0; i < 100; i++) {
let j = i;
setTimeout(function(){
console.log(j);
}, i*100);
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
I don't see anything wrong with any of these. JS is like the jazz of the programming world. :)
Option #2 is actually a textbook example of a closure and is great for private functions. That's a proper engineering interview question. :) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
var t= new Array(100).map(function(e,i){
return setTimeout(function(){
console.log(i);
//at this point we can access both the timeout index e (for clearing) and the array index i
//also the array of all timeouts t
},100);
});
//something went wrong, we must cancel them
t.forEach(function(e,i){
clearTimeout(e);
});
For other async code that's not a timeout the array would be an array of promises you can pass to Promise.all() for example.
The most elegant solution I can think of is using 'let', but that's already been mentioned by ben. :)
I usually see Option
#4 anonymous_self_executing.js
.I personally think it doesn’t matter which one you choose as long as you’re consistent throughout the project.