Asynchronicity within a loop
I'm using jQuery's $.getJSON()
API to retrieve data from a given URL for a set of utilities. I'd really like to find a way to reuse the code (it's all exactly the same) for each utility. Since the loop is executing without respect to the ajax call, I haven't been able to find a way to retain the looping value.
That description sucks, I know, so here'a a code snippet that defines it a little better:
var utility_types = [ 'Electricity', 'Gas', 'Water' ];
/** Retrieve known utility providers for the given zip code */
for( var i = 0; i < utility_types.length; i++ ) {
var type = utility_types[i];
$.getJSON( '/addresses/utilities/' + zip + '/' + type + '.json', null, function( data, status ) {
alert( 'Processing ' + type );
});
}
I need to find a way to pass the type value into the callback so I can apply the correct syntax. Without that, all 3 loops are executing against the "Water" utility. I know why it's 开发者_JAVA技巧not working, I'm just wondering whether there's a reasonable workaround.
Thanks.
Create a closure
var utility_types = [ 'Electricity', 'Gas', 'Water' ];
function getCallBack(type){
return function(data,status){
alert( 'Processing ' + type );
}
}
/** Retrieve known utility providers for the given zip code */
for( var i = 0; i < utility_types.length; i++ ) {
var type = utility_types[i];
$.getJSON( '/addresses/utilities/' + zip + '/' + type + '.json', null, getCallBack(type));
}
The canonical way of doing this whilst still using an anonymous closure is to create a new anonymous closure which is invoked immediately and passed the loop variable which then returns the real callback.
This anonymous closure has its own scope which contains its own variables (including the passed parameter) which may override the outer loop's variables, e.g.:
..., success: (function(type) {
return function() {
alert(type);
}
}(type))
The type
in the parentheses at the outside is the loop variable. The type
in the function declaration is a parameter which is in scope of the new closure. When alert
is called it uses the one that's closest in scope, i.e. the parameter.
Of course, the parameter can have its own variable name, it doesn't have to be the same as the one in the outer scope! If it were different then both would be available, but the outer scoped version would always have the same value.
you can assign the 'type' value to a member variable for each ajax request, and test it using the this
keyword in the callback success function:
var utility_types = [ 'Electricity', 'Gas', 'Water' ];
/** Retrieve known utility providers for the given zip code */
for( var i = 0; i < utility_types.length; i++ ) {
var type = utility_types[i];
var jsonReq = $.getJSON( '/addresses/utilities/' + zip + '/' + type + '.json', null, function( data, status ) {
alert( 'Processing ' + this.utilityType );
});
jsonReq.utilityType = type;
}
精彩评论