1

I'm getting this little trouble while looping, I always get the same "y" value (5) and it doesn't decreases or increases. What I want is to repeat the ajax call X times [all] and pass the response and the current call number thru an anonymous function. I hope you can help me.

function _shds(long, count, func) {
    for (var y = 0; y < count; y++) {
        gapi.client.load('urlshortener', 'v1', function() {
            var request = gapi.client.urlshortener.url.insert({
                'resource': {
                    'longUrl': long
                }
            });
            var resp = request.execute(function(resp) {
                func(resp.id, y);
            });
        });
    }
}
var total = 3;
var base = "soem";
var lista = ["1", "2", "3", "4", "5"];
_shds("222", total, function(data, y) {
    if (data != "undefined") {
        newbase = base.replace("soem", data);
        console.log(lista[y].uid + newbase + " pos:" + y);
    }
});​

UPDATE: Sorry, here's an example of the code: http://jsfiddle.net/ZgXZB/

5
  • try copying i to another variable then passing that variable to call. Something like var j = i; then call(data, j); Commented Jul 18, 2012 at 19:26
  • @MrOBrian JavaScript variables have function scope, not block scope. Commented Jul 18, 2012 at 19:27
  • Do you mean that you get 5 times the same answer from the server ? Commented Jul 18, 2012 at 19:29
  • @jtlebi exactly, because I want the value to change. Could you please check this jsfiddle? jsfiddle.net/ZgXZB Commented Jul 18, 2012 at 19:35
  • Well, the 5 times the same number problem is answered. Yet, the servers always gives back the same answer too because the request is the same. Same url to shorten leads back to the same short URL. Commented Jul 18, 2012 at 20:10

2 Answers 2

4

This is a trickier problem than it first appears, and a common JavaScript gotcha. What is going on is that when you say:

for (var y = 0; y < count; y++) {
    gapi.client.load('urlshortener', 'v1', function() {
        var request = gapi.client.urlshortener.url.insert({
            'resource': {
                'longUrl': long
            }
        });
        var resp = request.execute(function(resp) {
            func(resp.id, y);
        });
    });
}

You are creating a closure on y in the function callback that you pass to get. However, you only have created one closure and it has the final value of y which is count. What you want to do is create count different closures, so you need to introduce a new scope:

for (var y = 0; y < count; y++) {
 (function (y){      
  gapi.client.load('urlshortener', 'v1', function() {
      var request = gapi.client.urlshortener.url.insert({
          'resource': {
              'longUrl': longurl
          }
      });
      var resp = request.execute(function(resp) {
          func(resp.id, y);
      });
  });
 })(y);      
}

I believe that should do it. You need to declare a new function to create a new scope in JavaScript, and by passing y as a parameter to that function you are creating a new closure for each value of y.

Sign up to request clarification or add additional context in comments.

7 Comments

The fiddle is not working for me when I go to Run it, but I updated my code based on your new snippet. Does this solve your problem?
The fiddle just pushes content into console. Check it please, and it doesn't work with your code --> jsfiddle.net/ZgXZB/2
@Luis - Sorry about that, this one works much better - jsfiddle.net/ZgXZB/3
Sure it works, I will choose this answer but before that, can you correct the disorder while looping? Sometimes it throws 0, 2, 1, or 2, 0, 1. It's strange.
The ordering depends upon which web requests finish first, and is not guaranteed because everything is executing asynchronously. If you need to execute the functions in order, then you will need to have the callback store each result to an array and keep track of which ones are finished. When they are all complete, the last handler would then need to call another function to process the returned data. Again, that is only if you need to execute them in order...
|
2

The issue is that you are trying to get the value of i after the callbacks have returned, which is after your for-loop has finished. What you need to do is bind the value of i you want to pass to the callback when you first construct your intermediate callback for $.get:

function _short(longurl, count, func) {
    for (var y = 0; y < count; y++) {
        gapi.client.load('urlshortener', 'v1', function() {
            var request = gapi.client.urlshortener.url.insert({
                'resource': {
                    'longUrl': longurl
                }
            });
            var resp = request.execute((function(y, resp) {
                func(resp.id, y);
            }).bind(this, y));
        });
    }
}
var totalchat = 10;
var base = "soem";
var listachat = ["1", "2", "3", "4", "5"];
_short("222", 3, function(data, y) {
    if (data != "undefined") {
        newbase = base.replace("soem", data);
        console.log(listachat[y].uid + newbase + " pos:" + y);
    }
});

What bind does is create a new function where the value of this is bound to the first parameter (which I just set as this) and all remaining arguments are bound to the first arguments of the function, while the function it returns takes a new set of arguments (in this case, only the data argument remains from the original function, which matches the callback signature of $.get).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.