2010-04-02 20 views
6

He heredado código JavaScript donde la devolución de llamada exitosa de un manejador Ajax inicia otra llamada Ajax donde la devolución de llamada correcta puede o no iniciar otra llamada Ajax. Esto lleva a funciones anónimas profundamente anidadas. Tal vez haya un patrón de programación inteligente que evite la anidación profunda y sea más SECO. Además, existe el problema de las variables internas myVar1 y myVar2 que se utilizan en todas las funciones.¿Patrón de programación para aplanar callbacks ajax profundamente anidados?

jQuery.extend(Application.Model.prototype, { 
    process: function() { 
     var myVar1; 
     // processing using myVar1; 
     jQuery.ajax({ 
      url:myurl1, 
      dataType:'json', 
      success:function(data) { 
       var myVar2; 
       // process data using myVar1, set state of myVar2, 
       // then send it back 
       jQuery.ajax({ 
        url:myurl2, 
        dataType:'json', 
        success:function(data) { 
         // do stuff with myVar1 and myVar2 
         if(!data.ok) { 
          jQuery.ajax({ 
           url:myurl2, 
           dataType:'json', 
           success:mycallback 
          }); 
         } 
         else { 
          mycallback(data); 
          } 

        } 
       }); 
      } 
     }); 
    } 
}); 
+1

Ligeramente relacionado. Jugar AJAX "ping-pong" con el servidor es una forma segura de crear un tiempo de espera adicional. Es posible que desee considerar si es posible hacer el trabajo en una sola solicitud, incluso si eso significa transmitir más datos. – aaaaaaaaaaaa

Respuesta

3

Gracias a la sugerencia de encadenamiento y this comment, he llegado a la siguiente solución. Lo he probado y funciona. Probablemente haya algunos problemas de alcance y podría refactorizar una clase general de ChainAjax. Pero por el momento, esto está bien.

jQuery.extend(MyApplication.Model.prototype, { 
    process: function() { 

     // private class for executing the Ajax calls 
     var myAjaxCalls = function(options) { 
      this.options = options; 
      this.myVar1 = null; 
      this.myVar2 =null;     
     } 
     jQuery.extend(myAjaxCalls.prototype, { 
      process1:function(data) { 
      // processsing using this.myVar1 
      this.myVar1 = 5; 
      return true; 
      }, 
      process2:function(data) { 
      this.myVar2 = 6;  
      if(data.ok) { 
       mycallback(data); 
      } 
      else { 
       return true; 
      } 
      }, 
      process3:function(data) { 
      // Process this.myVar1 and this.myVar 
      mycallback(data); 
      return false; 
      }, 
      chainAjax:function() { 
      if(this.options.length > 0) { 
       var opt = this.options.shift(); 
       var that = this; 
       jQuery.ajax({ 
       url:opt.url, 
       success:function(data) { 
        if(that[opt.callback](data)) { 
          that.chainAjax(); 
        } 
       } 
       }); 
      } 
      } 
     }); 
     // End private class 

     var calls = new myAjaxCalls([ 
      {url:'http://localhost/', callback:'process1'}, 
      {url:'http://localhost/', callback:'process2'}, 
      {url:'http://localhost/', callback:'process3'} 
     ]); 
     calls.chainAjax(); 
    } 
}); 

Actualización: He encontradothis nice presentation que también se ocupa de la programación del dibujo útiles y mejores prácticas.

Actualización 2012: Mientras tanto hay varias bibliotecas para simular un flujo sincronizado con funciones asíncronas: q, stratified.js y streamline.js

9

No hay necesidad de que todas las devoluciones de llamada para ser anónimo y definida en línea, se puede declarar en otro lugar y sólo tiene que utilizar el nombre de la función cuando se especifica la devolución de llamada.

+0

+1 Me pegó. –

1

Sugeriría crear una pequeña herramienta llamada "cadena ajax". Le das lo que quieres que suceda en el orden y luego disparas. Cadena ajax en el éxito hasta que se acabe toda la lógica. Le ayudará a dejar de repetirse y solo representará el modelo lógico de lo que quiere hacer frente a la codificación de grunt.

0

Se puede hacer esto con Frame.js así:

jQuery.extend(Application.Model.prototype, { 
    process: function() { 
     var myVar1; 
     // processing using myVar1; 
     Frame(function(done){ 
      jQuery.ajax({ 
       url:myurl1, 
       dataType:'json', 
       success: done 
      }); 
     }); 
     Frame(function(done, data) { 
      var myVar2; 
      // process data using myVar1, set state of myVar2, 
      // then send it back 
      jQuery.ajax({ 
       url:myurl2, 
       dataType:'json', 
       success: done 
      }); 
     }); 
     Frame(function(done, data) { 
      // do stuff with myVar1 and myVar2 
      if(!data.ok) { 
       jQuery.ajax({ 
        url:myurl2, 
        dataType:'json', 
        success:done 
       }); 
      } 
      else { 
       done(data); 
      } 
     }); 
     Frame(function(done, data){ 
      mycallback(data); 
     }); 
     Frame.start(); 
    } 
}); 
Cuestiones relacionadas