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.
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.
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);
});
})();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With