Rob Wilkerson
Rob Wilkerson

Reputation: 41236

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 not working, I'm just wondering whether there's a reasonable workaround.

Thanks.

Upvotes: 5

Views: 196

Answers (3)

Alnitak
Alnitak

Reputation: 339816

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.

Upvotes: 3

doc_id
doc_id

Reputation: 1433

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;
}

Upvotes: 0

Zimbabao
Zimbabao

Reputation: 8240

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));
}

Upvotes: 3

Related Questions