2009-01-14 15 views
9

He una pieza de código jQuery que invoca varios getJSON() llamadas en rápida sucesión:condición de alcance o la carrera de jQuery en AJAX/getJSON

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

Cuando ejecuto esto en contra de un servidor lag, la tabla se rellena con el valores json.someMember esperados (llegan fuera de servicio: no me importa), pero la columna thisItem está poblada con una mezcla impredecible de valores de varias iteraciones.

Supongo que esto tiene algo que ver con el alcance y el tiempo: ¿la función de devolución de llamada está leyendo thisItem desde un alcance más amplio? ¿Estoy en lo cierto? ¿Cómo evito esto?

Mi solución actual es que el servicio JSON devuelva una copia de sus entradas, lo que es insatisfactorio por decir lo menos.

+0

Gracias Slim por hacer esta pregunta. También tuve algunos problemas (era consciente de que la función asincrónica regresa pero no estoy seguro de cómo señalar a la llamada getJSON qué ubicación colocará un valor de retorno). –

Respuesta

12

Parece un problema de alcance debido al ciclo. Prueba esto:

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

Edición: todo lo que hice fue thisItem alcance a la $.getJSON de devolución de llamada.

+0

No creo que esto funcione con jQuery. ¿Acaso el JSON no pasaría al cierre en lugar de la variable thisItem y causaría un error? – jacobangel

+1

No. $ .getJSON se pasa la función interna; el que obtiene el parámetro "json". –

+0

Parece haber funcionado bien (¡después de ordenar todas las llaves!). ¡Gracias! – slim

3

JavaScript no utiliza el bloque para el alcance. El alcance solo se basa en funciones.

Si desea un nuevo ámbito, debe declarar una nueva función interna y ejecutarla de inmediato, esta es la única forma de crear un nuevo ámbito en 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); 
     }); 
    })(); 
} 
+0

Me gusta esta solución ya que me permite tener más variables locales como thisItem, sin una firma de función detallada. – slim

+0

hecho de la diversión: así es como normalmente se implementa el alcance en el Esquema – Javier

+0

Olvidé de otra manera, podría usar un bucle for desde una biblioteca, estos realmente toman una función como el bloque para ejecutar en cada iteración. En jQuery: $ .each (items, function (i, item) {...}); –

Cuestiones relacionadas