2012-06-10 22 views
15

Tengo un problema con la función $ .get. La URL contiene JSONHacer que la función "get" de AJAX sea sincrónica/¿cómo obtener el resultado?

mi código:

xyz = null 

    $.get('http://www.someurl.com/123=json', function(data) { 
     var xyz = data.positions[0].latitude; 
    }); 

alert(xyz); 
//some more code using xyz variable 

Sé que xyz alertará a un resultado nulo porque el $.get es asíncrono.

Entonces, ¿hay alguna forma de que pueda usar el xyz fuera de esta función get?

+0

Si mueve la palabra clave 'var' de su función y frente a su 'xyz' inicial, entonces puede usarlo en cualquier parte de ese alcance en cualquier función que se ejecute después de que se complete su solicitud de ajax. – Paulpro

+4

Si bien * está * ** sincrónico ** AJAX (está * documentado * en jQuery), normalmente * se debe evitar * debido al impacto negativo que tiene en la experiencia del usuario. En cambio, concéntrese en usar el modelo basado en eventos de AJAX asíncrono. Es decir, actualice el DOM con 'xyz' * desde * la devolución de llamada. –

+0

@pst. La misma pregunta todo el tiempo. Éste y el problema listo DOM. – gdoron

Respuesta

7

La verdadera respuesta es NO , pero se puede usar esto:

function useXYZ(){ 
    alert(xyz); 
} 

xyz = null   

$.get('http://www.someurl.com/123=json', function(data) { 
    xyz = data.positions[0].latitude; 
    useXYZ(); 
}); 
+0

¿Por qué perder el tiempo y la confusión mental en una propiedad global? (O variable cerrada). A menudo se escribe mejor como 'function useXYZ (xyz) {..}' ... y luego pasa a través de los datos de la devolución de llamada. –

+0

@pst. Pensé que lo haría, pero quería mostrarle cómo puede usar la variable externa. (Por cierto, no tiene que ser una variable global). ¡Puede editar como lo desee, señor! – gdoron

+0

Gracias! Aunque creo que funciona bien con alerta, sigo teniendo problemas con el resto del guión. Y de hecho, cuando tengo que poner muchas cosas dentro de la función, uso XYZ() {...} – Diolor

22

get es un atajo. Usted puede hacer lo mismo, pero sincrónica, usando:

var xyz = null 


$.ajax({ url: 'http://www.someurl.com/123=json', 
     async: false, 
     dataType: 'json', 
     success: function(data) { 
       xyz = data.positions[0].latitude; 
      } 
     }); 


alert(xyz); 

Vas a tener que declarar la variable xyz antes de la llamada ajax, sin embargo.

+0

Bueno, honestamente, mi respuesta inicial fue pobre. Realmente debería dejar de intentar responder preguntas desde mi teléfono. – HackedByChinese

+0

En Chrome y Firefox todavía estoy obteniendo un nulo. En safari funciona bien – Diolor

+0

Hmm. Lo he probado con Safari, Chrome y Firefox (en OSX). Aquí hay un ejemplo puro http://jsfiddle.net/HackedByChinese/F2Ey5/1/ – HackedByChinese

4

Este es un problema común con Javascript. El código de Javascript debe escribirse con el estilo de paso de continuación. Es molesto, pero es algo que puedes convertir sin pensar demasiado.

Básicamente, cada vez que tendríamos algo así como

var x = someSyncFunction(a, b, c); 
//do something with x 
console.log(x); 

Podemos convertirlo en código asíncrono al hacer todo el código después de la función devuelve en una función de continuación y girando x partir de una variable en un parámetro de la devolución de llamada de continuación.

someAsyncFunction(a, b, c, function(x){ 
    //do something with x; 
    console.log(x); 
}); 

Tiene que tener en cuenta que es muy fácil escribir código confuso. Un buen truco para tener en cuenta es que puede hacer que sus propias funciones también reciban devoluciones de llamada. Esto permite que sean utilizados por la función diferente (al igual que las funciones normales de sincronización de ayuda que devuelven un valor puede ser utilizado por diferentes funciones)

var getXyz = function(onResult){ //async functions that return do so via callbacks 
           //you can also another callback for errors (kind of analogous to throw) 
    $.get('http://www.someurl.com/123=json', function(data) { 
     var xyz = data.positions[0].latitude; 
     onResult(xyz); //instead of writing "return xyz", we pass x to the callback explicitely. 
    }); 
}; 

getXyz(function(xyz){ //this would look like "var xyz = getXyz();" if it were sync code instead. 
    console.log('got xyz'); 
}); 

El truco aquí es cambiar todas las declaraciones de retorno de la función en las llamadas a la función de devolución de llamada. Piense como si la función de sincronización nunca regresara y la única forma de devolverle un valor a alguien es pasar ese valor a una devolución de llamada.


Puede que pregunte por qué no hay una manera más fácil de hacer todo esto. Bueno, no hay, a menos que use otro idioma en lugar de Javascript (o al menos algo que le permite escribir código asíncrono en estilo sincrónico pero compila automáticamente a Javascript regular)

+0

¡Gracias! ¿Qué pasaría si tuviera que tomar dos vars del JSON como "xyz" para la latitud y "abc" para la longitud? Cómo sería onResult y funcionaría (xyz). ¿Podría anidarlos dentro de él o debería crear una segunda función (abc)? – Diolor

+0

Puede empaquetar ambos valores dentro de un solo objeto y pasar el objeto a la devolución de llamada 'onResult ({lat: xyz, long: abc});', de forma similar a como devolvería múltiples valores de una función síncrona) o podría tener la función de devolución de llamada recibe dos parámetros en lugar de uno 'onResult (xyz, abc);'. Tener más de una devolución de llamada es generalmente para rutas de cálculo diferentes y mutuamente excluyentes. Un ejemplo común es tener una devolución de llamada de éxito (o "devolución") y una devolución de llamada de error (o "lanzar"). – hugomg

Cuestiones relacionadas