Question

I have a piece of jQuery code which invokes several getJSON() calls in quick succession:

var table = $("table#output");
for (var i in items) {
    var thisItem = items[i];
    $.getJSON("myService", { "itemID": thisItem }, function(json) {
        var str = "<tr>";
        str += "<td>" + thisItem + "</td>";
        str += "<td>" + json.someMember + "</td>";
        str += "</tr>";
        table.append(str);
    });
}

When I run this against a laggy server, the table gets populated with the expected json.someMember values (they arrive out of order: I don't mind that), but the thisItem column is populated with an unpredictable mixture of values from various iterations.

I'm assuming this is something to do with scope and timing - the callback function is reading thisItem from a wider scope? Am I right? How do I prevent this?

My current workaround is for the JSON service to return a copy of its inputs - which is unsatisfying to say the least.

Was it helpful?

Solution

Seems like a scoping issue due to the loop. Try this:

var table = $("table#output");
for (var i in items) {
    var thisItem = items[i];
    $.getJSON("myService", { "itemID": thisItem }, (function(thisItem) {
        return function(json) {
            var str = "<tr>";
            str += "<td>" + thisItem + "</td>";
            str += "<td>" + json.someMember + "</td>";
            str += "</tr>";
            table.append(str);
        }
    })(thisItem));
}

Edit: all I did was scope thisItem to the $.getJSON callback.

OTHER TIPS

Javascript does not use block for scope. Scope is only based on functions.

If you want a new scope, you have to declare a new internal function and run it immediately, this is the only way to create a new scope in Javascript.

var table = $("table#output");
for( var i in items ) 
{
    (function(){
        var thisItem = items[i];
        $.getJSON("myService", { "itemID": thisItem }, function(json) 
        {
            var str = "<tr>";
            str += "<td>" + thisItem + "</td>";
            str += "<td>" + json.someMember + "</td>";
            str += "</tr>";
            table.append(str);
        });
    })();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top