2010-05-12 33 views
5

Las llamadas asincrónicas secuenciales son brutas. ¿Hay una solución más legible?¿Cómo se evitan las funciones anidadas cuando se usa AJAX?

El problema es que esto es difícil de seguir:

ajaxOne(function() { 
    // do something 
    ajaxTwo(function() { 
    // do something 
    ajaxThree() 
    }); 
}); 

donde las funciones anónimas son devoluciones de llamada que se denominan en la respuesta del servidor.

Estoy usando una API de terceros para realizar llamadas AJAX, por lo que necesito una solución genérica.

Respuesta

3

programación funcional para el rescate! jsdeferred le permite escribir sus ejemplo, así:

next(ajaxOne).next(ajaxTwo).next(ajaxThree).error(function(e){alert('An error happened:' + e)}) 

cada uno de los "secuencial" ajaxOne/dos/tres funciones recibe el resultado devuelto de su predecesor como parámetro. Si necesita pasar parámetros adicionales, puede exponerlos en un objeto global antes de invocar su cadena AJAX.

+0

Aunque ese enfoque requiere mucho más esfuerzo, es seguro y muy bueno :) Pero en realidad no es una cuestión de "programación funcional". – selfawaresoup

+0

Esto se ve muy bien, pero no puedo entender cómo funciona la clase diferida internamente. –

+0

Un vistazo a la fuente de jsdeferred (http://github.com/cho45/jsdeferred/blob/master/jsdeferred.js) le dice que la siguiente función simplemente espera que llegue la primera llamada ajax (usando setTimeout) y luego envía el siguiente. – fbuchinger

1

Si solo tiene una función anidada, está bien que la deje como está, pero si tiene varias llamadas anidadas, debería considerar escribir estas devoluciones de llamadas en un método diferente y llamarlo desde la función anidada ...

ajaxOne(function(result) { handleAjaxOneCallback(result, someExtraNeededArg); }); 

function handleAjaxOneCallback(result, someExtraNeededParam) { 
    // do something 

    ajaxTwo(function(result) { handleAjaxTwoCallback(result, myFoo, myBar); }); 
} 

function handleAjaxTwoCallback(result, foo, bar) { 
    // do something 

    ajaxThree(/* ... */); 
} 
0

Si no necesita el alcance del cierre en sus devoluciones de llamada, que probablemente no lo hará, puede poner las devoluciones de llamada en funciones separadas y llamarlas por su nombre. como:

var ajaxOne = function() { 
    doTheAjax(callbackOne); 
} 
var callbackOne = function() { 
    //funny things ... 
    doTheAjax(callbackTwo); 
} 
var callbackTwo = function() { 
    //even more funny things ... 
} 
+0

Mi pregunta probablemente fue pobremente formada. Este es en realidad el método que uso ya que la línea se volvería demasiado grande en mi ejemplo. Sin embargo, la lógica es difícil de seguir porque las llamadas aún deben rastrearse. –

1

Primero tengo que admitir que soy relativamente nuevo en JavaScript, pero recientemente encontré el mismo problema al usar la función jQuery ajax. Tuve que subir un par de documentos a través de POST a un servidor en un cierto orden. Anidar todas las devoluciones de llamada habría producido un código completamente desordenado. Pensé en una solución después de leer las respuestas y encontré una solución que me funcionó bien. Utiliza una única función con una cláusula de cambio a diferenciar las distintas invocaciones de devolución de llamada:

var callback = function(sCallIdentifier, callbackParameters){ 
    switch(sCallIdentifier){ 
    case "ajaxOne": 
     doYourStuff(callbackParameters); //do your stuff for ajaxOne 
     ajaxTwo(function(newCallbackParameters){ 
      /*define a anonymous function as actual method-callback and pass the call-identifier, together with all parameters, to your defined callback function*/ 
      callback("ajaxTwo", newCallbackParameters); 
     }); 
     break; 
    case "ajaxTwo": 
     doYourStuff(callbackParameters); 
     ajaxThree(function(newCallbackParameters){ 
      callback("ajaxThree", newCallbackParameters); 
     }); 
     break; 
    case "ajaxThree": 
     doYourStuff(); 
     break; 
} 
}); 

Si esto no es una buena idea, por favor hágamelo saber. Como dije, no soy un experto en JavaScript, pero funcionó bastante bien para mí.

mejor, René

Editar:

Después de un tiempo descubrí que Promises son un enfoque mucho mejor para resolver este problema.

Cuestiones relacionadas