Tengo que interactuar con la api remota que me obliga a la cadena de las solicitudes. Eso es una devolución de llamada-el infierno en modo asíncrono:

//pseudocode: ajax(request_object, callback)
ajax(a, function() {
  ajax(b(a.somedata), function() {
    ajax(c(b.somedata), function() {
      c.finish()
    }
  }) 
})

Sería mucho más legible en el modo de sincronización:

sjax(a)
sjax(b(a.somedata))
sjax(c(b.somedata))
c.finish()

Pero Sjax es malo 🙂 ¿Cómo puedo hacer que en una buena no-tan-mal y legible?

  • Por qué habría alguien de downvote esta pregunta?
  • Vi como el OP fue downvoting todas las respuestas. Así que me votada abajo a la pregunta.
  • OP no tiene downvotes en su perfil.
  • Mi mal entonces .
InformationsquelleAutor defnull | 2009-06-15

9 Comentarios

  1. 16

    No utilice funciones anónimas. Les damos nombres. No sé si eres capaz de hacer lo que escribí a continuación: la

    var step_3 = function() {
        c.finish();
    };
    
    var step_2 = function(c, b) {
        ajax(c(b.somedata), step_3);
    };
    
    var step_1 = function(b, a) {
      ajax(b(a.somedata), step_2);
    };
    
    ajax(a, step_1);
  2. 23

    Usted podría tener una sola función que se le pasa un entero para el estado de lo que paso la petición, a continuación, utilizar una instrucción switch para averiguar lo que es necesario solicitar hacer la siguiente:

    function ajaxQueue(step) {
      switch(step) {
        case 0: $.ajax({
                  type: "GET",
                  url: "/some/service",
                  complete: function() { ajaxQueue(1); } 
        }); break;
        case 1: $.ajax({
                  type: "GET",
                  url: "/some/service",
                  complete: function() { ajaxQueue(2); }
                }); break;
        case 2: $.ajax({
                  type: "GET",
                  url: "/some/service",
                  complete: function() { alert('Done!'); }
                }); break;
      }
    }
    
    ajaxQueue(0);

    Espero que ayude!

    • Usted no puede dar argumentos a los valores predeterminados de esta manera. Pero me gusta la solución.
    • Oh maldito lo siento, ha sido la programación de un montón de PHP recientemente y mi JavaScript oxidado. Publicado actualizado con la sintaxis correcta 🙂
    • ASP.NET 3.5 los WebServices se configura como este. Todos los WebMethods en el JS lado tiene un defecto de función de devolución de llamada (bueno, si lo pones de esa forma), y puede cambiar en el nombre del método llamado en el servidor para decidir qué hacer con la respuesta. Una cosa que podría cambiar con este ejemplo es para que no pase alrededor de los números, pero en lugar de utilizar más de una enumeración enfoque: ajaxQueue(cualquier_nombre); para saber lo que su llamada a la función que está haciendo.
    • Me gusta este también. +1
  3. 5

    Esta función debe encadenar una lista de peticiones ajax, si las devoluciones de llamada devuelva siempre los parámetros necesarios para la solicitud siguiente:

    function chainajax(params, callbacks) {
      var cb = shift(callbacks);
      params.complete = function() {
        var newparams = cb(arguments);
        if (callbacks)
          chainajax(newparams, callbacks);
      };
      $.ajax(params);
    };

    Puede definir estas funciones de devolución de llamada por separado y, a continuación, la cadena de ellos juntos:

    function a(data) {
      ...
      return {type: "GET", url: "/step2.php?foo"}
    };
    //...
    function d(data) { alert("done!"); };
    
    chainajax({type: "GET", url: "/step1.php"},
      [a, b, c, d]);

    También podría declarar las funciones «inline» en la llamada a chainajax, pero que podría ser un poco confuso.

  4. 4

    Tal vez lo que puedes hacer es escribir un server-side función de contenedor. De esa manera que el javascript que sólo se hace una sola llamada asincrónica a su propio servidor web. A continuación, el servidor web utiliza curl (o urllib, etc.) para interactuar con la API remota.

    • +1 para simplificar el lado del cliente
    • urllib en el servidor – mucho más difíciles de leer que anidados devoluciones de llamada del cliente. =)
  5. 3

    Actualización: he de aprender una mejor respuesta para esto si usted está usando jQuery, ver mis actualizaciones, bajo el título: el Uso de jQuery Diferido

    Viejo respuesta:

    También puede utilizar Array.reduceRight (cuando está disponible) para envolver el $.ajax llamadas y transformar una lista como: [resource1, resource2] en $.ajax({url:resource1,success: function(...) { $ajax({url: resource2... (un truco que he de aprender de Haskell y es plegable/foldRight función).

    Aquí está un ejemplo:

    var withResources = function(resources, callback) {
        var responses = [];
        var chainedAjaxCalls = resources.reduceRight(function(previousValue, currentValue, index, array) {
            return function() {
                $.ajax({url: currentValue, success: function(data) {
                    responses.push(data);
                    previousValue();
                }})
            }
        }, function() { callback.apply(null, responses); });
        chainedAjaxCalls();
    };

    A continuación, puede utilizar:

    withResources(['/api/resource1', '/api/resource2'], function(response1, response2) {
        //called only if the ajax call is successful with resource1 and resource2
    });

    Usando jQuery Diferido

    Si usted está usando jQuery, usted puede tomar ventaja de jQuery Diferido, mediante el uso de la jQuery.when() función:

     jQuery.when($.get('/api/one'), $.get('/api/two'))
           .done(function(result1, result2) { 
                  /* one and two is done */
            });
    • Este es un bonito, fácil de seguir JQuery explicación – medium.com/coding-design/writing-better-ajax-8ee4a7fb95f – tenga en cuenta la sección cómo usted también puede asignar un $.ajax() llamada a una variable, y luego llamar a la .hecho() método que, como una forma rápida para evitar la sangría.
  6. 2

    Creo que la implementación de una máquina de estado va a hacer el código más legible:

    var state = -1;
    var error = false;
    
    $.ajax({success: function() { 
                      state = 0;
                      stateMachine(); },
            error: function() {
                      error = true;
                      stateMachine();
            }});
    
    function stateMachine() {
      if (error) {
         //Error handling
         return;
      }
    
      if (state == 0) {
        state = 1;
        //Call stateMachine again in an ajax callback
      }
      else if (state == 1) {
    
      }
    }
    • Si es posible, se debe evitar el uso de variables globales. Jamie Rumbelow la solución es un poco más elegante.
  7. 1

    Hice un método que utiliza las Promesas

    JS:

    //How to setup a chainable queue method
    var sequence = Promise.resolve();
    
    function chain(next){
        var promise = new Promise(function(resolve){
            sequence.then(function(){
                next(resolve);
            });	
        });
    
        sequence = promise;
    }
    
    //How to use it
    chain(function(next){
        document.write("<p>start getting config.json</p>");
        setTimeout(function(){
        	document.write("<p>Done fetching config.json</p>");
            next();
        }, 3000);
    });
    
    chain(function(next){
        document.write("<p>start getting init.js</p>")
        setTimeout(function(){
            document.write("<p>starting eval scripting</p>");
            next();
        }, 3000);
    });
    
    chain(function(next){
        document.write("<p>Everything is done</p>");
    });


    Bono: Un ultraligth 138 byte limitada de Una Promesa (que sólo puede resolver – sin parámetros, y sólo llame a la última, a continuación, el método )

    Fondo:
    Hice esto para node.js en el punto en que la dosis no tienen promesas de un CAJERO automático. Yo no quería un completo soplado Promesa de la biblioteca que estaba a cargo y tuvo que incluir en mi paquete.json, yo la necesitaba para ser rápido y ligero, y sobre todo de una cosa. Yo sólo necesitaba para una cosa (encadenamiento de las cosas como quiere)

    function Q(a,b){b=this;a(function(){b.then&&b.then();b.then=i});return b}function i(a){a&&a()}Q.prototype={then:function(a){this.then=a}};

    Cómo?

    //Start with a resolved object
    var promise = new Q(function(a){a()});
    //equal to 
    //var promise = Promise.resolve();
    
    //example usage
    new Q(function(resolve){
        //do some async stuff that takes time
        //setTimeout(resolve, 3000);
    }).then(function(){
        //its done
        //can not return a new Promise
    }); //<- can not add more then's (it only register the last one)

    y para la conexión en cadena de la cola método

    //How to setup a chainable queue method with ultraligth promise
    var sequence = new Q(function(a){a()});
    
    function chain(next){
        var promise = new Q(function(resolve){
            sequence.then(function(){
                next(resolve);
            }); 
        });
    
        sequence = promise;
    }
  8. 0

    La completa devolución de llamada es lo que estás buscando:

    $.ajax({
         type: 'post',
         url: "www.example.com",
         data: {/* Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. */},
         success:
              function(data) {
                  /* you can also chain requests here. will be fired if initial request is successful but will be fired before completion. */
              },
        complete: 
             function() {
                 /* For more a more synchronous approach use this callback. Will be fired when first function is completed. */
             }
    });

Dejar respuesta

Please enter your comment!
Please enter your name here