Ambito o condizione di competizione jQuery in AJAX / getJSON
-
22-07-2019 - |
Domanda
Ho un pezzo di codice jQuery che invoca diverse chiamate getJSON ()
in rapida successione:
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);
});
}
Quando eseguo questo su un server ritardato, la tabella viene popolata con i valori previsti json.someMember
(arrivano fuori servizio: non mi dispiace), ma il thisItem
è popolato con una miscela imprevedibile di valori da varie iterazioni.
Suppongo che ciò abbia a che fare con l'ambito e i tempi: la funzione di callback sta leggendo thisItem
da un ambito più ampio? Ho ragione? Come posso impedirlo?
La mia attuale soluzione alternativa è che il servizio JSON restituisca una copia dei suoi input, il che è insoddisfacente per non dire altro.
Soluzione
Sembra un problema di scoping dovuto al loop. Prova questo:
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));
}
Modifica : tutto quello che ho fatto è stato ambito thisItem
sul callback $ .getJSON
.
Altri suggerimenti
Javascript non utilizza il blocco per ambito. L'ambito si basa solo sulle funzioni.
Se si desidera un nuovo ambito, è necessario dichiarare una nuova funzione interna ed eseguirla immediatamente, questo è l'unico modo per creare un nuovo ambito 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);
});
})();
}