Usando $.Diferidos() anidados llamadas ajax en un bucle

He pasado demasiadas horas buscando similares preguntas y tratando de soluciones, así que espero que alguien tiene una solución.

Básicamente, me gustaría ser notificado cuando una función a() ha terminado. El problema es que la función contiene una llamada ajax y un bucle en el que llama a b(), que a su vez contiene una llamada ajax.

ACTUALIZADO CON EL VIOLÍN: http://jsfiddle.net/hsyj7/1/

Así:

//called by main()
function a() {
  return $.ajax("http://url1").pipe(function(data){
    for (var i = 0; i < 2; i++) {
      console.log('a called');
      b();
    }
  });
}

//called by a()
function b() {
  for (var i = 0; i < 2; i++) {
    $.ajax("http://url2", function(data){
      //do something
      console.log('b called');
    }
  }
}

function main(){
  $.when(a()).done(function(){
    console.log('all completed');
  });
}

Lo que me gustaría a ver a continuación, es, posiblemente con ambas llamadas a un() en la parte superior:

a called
b called
b called
a called
b called
b called
all completed

Lugar puedo conseguir

a called
all completed
b called
b called

O alguna variante del mismo.

Soy consciente de que el código anterior es la falta de aplazar la funcionalidad tanto en el bucle y en b().
En algunas de las variantes que he probado, el hecho() controlador en main() nunca es llamado.

Cualquiera sabe cómo hacer esto?

  • La única solución que se me ocurre es algún tipo de contador que disminuye como el de las llamadas AJAX de retorno y luego dispara un complete evento cuando llega 0. Yo no soy de publicar que como una respuesta como tiene que ser algo más elegante 🙂
  • Aquí un violín de la pregunta: jsfiddle.net/pxVAE
  • Yo tenía una pregunta similar, que no estaba del todo resuelto. – stackoverflow.com/questions/12273437/…
  • ¿Usted también desea ejecutar b() en secuencia o en paralelo? I. e. ¿quieres esperar para b para terminar antes de llamar una segunda vez?
InformationsquelleAutor jokkedk | 2012-12-19

4 Kommentare

  1. 29

    Sí, utilizando Deferred es la manera de hacerlo:

    function a() {
        var def = $.Deferred();
    
        $.ajax("http://url1").done(function(data){
            var requests = [];
    
            for (var i = 0; i < 2; i++) {
                 requests.push(b());
            }
    
            $.when.apply($, requests).then(function() { def.resolve(); });
        });
    
        return def.promise();
    }
    
    //called by a()
    function b() {
        var def = $.Deferred(),
            requests = [];
    
        for (var i = 0; i < 2; i++) {
            requests.push($.ajax("http://url2").done(function(data){
                //do something
                console.log('b called');
            });
        }
    
        $.when.apply($, requests).then(function() { def.resolve(); });
    
        return def.promise();
    }
    
    function main(){
        $.when(a()).done(function(){
            console.log('all completed');
        });
    }

    //EDIT: se ha Sustituido .pipe con .done.

    • Me gustaría +1, pero yo estoy fuera de votos. Sólo FMI, con lo que se logró mediante el uso de pipe() en a() (o, en este caso es sinónimo de uso de then()?)
    • En este trozo de código? Absolutamente nada. Supongo que es un fragmento de la pieza más grande de código.
    • Gracias @estrafalario, que funciona! Mi confusión fue cuando el uso de resolve() y la promesa() en los bucles.
    • -1 para que no de errores de manejo. También, por qué no se utiliza el pipe método cuando no se utilizan?
    • Se supone que tengo que escribir todo el código de OP? Sencillamente, he mostrado cómo lograr lo que quiere.
    • No, pero sería de gran ayuda si las malas prácticas de construcción de $.Deferreds no se transmite 🙂
    • Estoy de acuerdo ( voy a actualizar a la pregunta una vez que tengo el tiempo suficiente para recordar lo que fue incluso sobre 😀 ). Sin embargo, desde hace responder a la pregunta creo que no merece -1.
    • Creo (alta votado) mala-práctica respuestas son un peligro (a la >1k de los espectadores), por lo que he pulsado «respuesta no es útil«. Estoy deseando ver lo corrijan!
    • Me he fijado. Debe estar bien ahora.
    • El uso de pipe no fue el problema, es que hubiera sido la solución, en realidad. El problema es crear y resolver deferreds. Es posible que desee tener un vistazo de mi respuesta.
    • Entonces estamos completamente de acuerdo. Te has mudado a una gran parte de la función a() fuera de ella. Lo que si es llamado en algún otro lugar directamente? Yo no puedo estar de acuerdo con tales refactorización. No debemos modificar el código original más de lo necesario.
    • Asegúrese de verificar el update. Esta trivialidad de que el cambio es la razón para utilizar then para componer acciones asincrónicas.
    • Veo, parece estar bien ahora (todavía hay muchas cosas para mí para aprender acerca de jQuery, de verdad). Sin embargo no estoy de acuerdo que el uso de deferreds directamente es un problema. No? Sí. Incorrecta? No. Es sólo otra solución para el problema. Voy a dejar la respuesta tal y como es. La gente puede utilizar su solución, no me importa. Incluso me voy a upvote.
    • Es una propenso a errores de diseño. La gente se olvida de rechazar la deferreds cuando se les necesita – al igual que usted tiene. El uso de then automáticamente se encarga de eso.
    • Yo no olvidarse de él – simplemente no les importa. Estoy de acuerdo en que es propenso a errores, pero eso no significa que es incorrecta. La solución podría ser mejor, pero eso no significa que la mina está mal.
    • con referencia a su respuesta he intentado un ejemplo para ejecutar un diferida en función de bucle. Sin embargo, el resultado no está funcionando como se esperaba. Consulte – jsfiddle.net/fewtalks/nvbp26sx/1. Esto imprime a la salida como {{ procesados test1 elemento 0; procesado test1 el punto 1; procesado de elementos de prueba 0; procesado de elementos de prueba 1; completado}} . Sin embargo, yo a esperar la salida como {{ procesados test1 item0 procesados prueba item0; procesado test1 elemento1; procesado de prueba item0}}. ¿Por qué el aplazamiento de la prueba de función no se está ejecutando después de prueba1 se ha completado.
    • Puesto esto como una nueva pregunta (con el código completo copiado allí) y vamos a tener una mirada en ella. Es difícil leer tu comentario ¿cuál es el resultado esperado.
    • href=»http://stackoverflow.com/questions/38468428/jquery-deferred-in-each-loop-with-ajax-callback» title=»jquery diferidos en cada bucle con el ajax de devolución de llamada»>stackoverflow.com/questions/38468428/…

  2. 2

    Se podría utilizar un Matriz que se encuentra en un contexto superior a empujar Promesa /Diferido objetos. A continuación, puede utilizar jQuery.when junto Function.prototype.apply a pasar todas las entradas como argumentos.

    (function() {
        var promises = [ ],
            when = Function.prototype.apply.bind( jQuery.when, null );
    
        function a() {
             promises.push($.ajax("http://url1").pipe(function(data){
                 for (var i = 0; i < 2; i++) {
                     console.log('a called');
                     b();
                 }
             }));
    
             return promises;
        }
    
        function b() {
            for (var i = 0; i < 2; i++) {
                promises.push($.ajax("http://url2", function(data) {
                    //do something
                    console.log('b called');
                }));
            }
        }
    
        function main() {
            promises = [ ];
    
            when( a() ).done(function(){
                console.log('all completed');
            });
        }
    }());
    • -1: Varias llamadas a a va a provocar una pérdida de memoria, porque promises es un «global» de la lista.
    • no es una lista global. OP no dicen nada acerca de varias llamadas. Incluso si ese fue el caso, se trataría sólo de empujar más objetos en el Array, que definitivamente no es un pérdida de memoria. Él sólo necesita re-initialize el Array. -1 para que? Está usted bromeando ?
    • Es por eso que escribí la en quation marcas. Mundial de a y b punto de vista. OP claramente dio el ejemplo de a ser llamado dos veces. La pérdida de memoria es no, porque sólo de empujar a promises.
    • mejor google para la definición de un pérdida de memoria bro, empujando los datos en una matriz que no es sólo eso. Pero, de nuevo, que restablezca a un vacío de Array está abierto para todos. De nuevo, esto no es un downvote. Está usted bromeando..
    • Entonces, ¿por qué no incluyen el restablecimiento en su solución? El código de pérdidas de memoria cuando llama varias veces. Verdadero o falso? No entiendo por qué usted está constantemente tratando de burlarse de mí. Escribir la solución adecuadamente, entonces voy a upvote.
    • En realidad, a() sólo se llama una vez en la OP del ejemplo. Y puesto que todas las funciones en jAndy solución está dentro de una expresión de función, ninguno de ellos puede en realidad se llama 😉 Que más vale la pena de ser señalado 🙂
    • Oh, tienes razón. Lo siento, pensé que console.log es antes de bucle. Justo lo suficiente, voy a upvote ahora.
    • Yo no quiero un flamewar. Pero deberías volver a pensar en su comportamiento. Su redacción en este ECMAcript contexto es bastante cuestionable (cotización o no y sobre las pérdidas de memoria) + el hecho de que no declaró la función es conseguir que llama más de una vez.
    • Volver a pensar en mi comportamiento? Soy muy paciente y amable. Yo no soy tu «hermano» y me gusta usar quation marcas ( que no es difícil de entender, en serio ) y no me burlarse de otras personas. Tal vez debería volver a pensar en su comportamiento? Ahora he cometido un error y me disculpo.
    • Cierto, sin embargo, todos sabemos, que esto es sólo un fragmento de código, y tal vez esto está vinculado a algún evento. De todos modos potencialmente puede conducir a la pérdida de memoria.
    • Creo que incluso se podría ámbito y volver promises en el interior tanto de a() y b(), para deshacerse de estado del contexto en total
    • Exactamente, es sólo un fragmento… no hay necesidad de rumble demasiado acerca de él… facilidad en todo el mundo, es tiempo de Navidad 🙂
    • Yo no tenía ninguna diversión de usted, yo estaba sorprendido de que yo en serio tengo un downvote, con que motivo. La razón no era correcto o verdadero (por definición), así que eso es lo que yo llamo un mal comportamiento en este sitio.
    • ¿a qué te refieres con ninguno de ellos puede en realidad se llama ? Código funciona como se esperaba.
    • Donde estás llamando main()?
    • ¿de dónde viene el OP llaman ?
    • Bueno, yo sólo quería señalar que ninguna de las funciones a, b y main son accesibles desde el exterior de todo el bloque de código. Así, suponiendo OP llamadas main algún, el cual no se encontró con su código.
    • Jeje, así que tal vez debemos ser muy estrictos y por definición ( lo que significa ) respuesta de que el código funciona correcto, porque no se llama a cualquier lugar. Pregunta cerrada. Debido a que el OP no el estado. Eres tan testarudo, mientras que todo el mundo sabe que el código que nos han mostrado potencialmente conduce a la pérdida de memoria. También puede ser fácilmente corregido, así que no entiendo todo este ataque. Y dejar de ofender a mí todo el tiempo. No es correcto? No es cierto? B***ch, por favor.
    • Realmente creo que soy bastante abierta de mente y no contumaz. Pero usted acaba de «asumir» las cosas y en base a eso, predecir pérdidas de memoria (que aun no existen pérdidas de memoria, todavía, por definición) y peligrosamente el tonto con palabras como la, que se utiliza generalmente en una manera completamente diferente. Que además, por supuesto, la downvote para este cuestionable comportamiento general. ¿Qué esperas que yo haga ? Decir gracias ?
    • Es tan difícil asumir que? Es tan poco probable que suceda? Usted hizo suponer que main se llama en algún lugar, a la derecha ( de lo contrario el código funciona por definición )? Así que supuse que es posiblemente llamado varias veces. ¿Cómo es diferente? Y qué tienes que ser tan terco sobre «global» de la palabra, la gramática freak? Por no hablar de que también debemos enseñar buenas prácticas y lo que nos han mostrado no es ni siquiera cerca. Usted no tiene que decir nada, sólo arreglar su solución. OK, eso es todo para mí. No voy a discutir más, como Félix dijo es tiempo de Navidad después de todo. Feliz Navidad!
    • no es difícil, pero muy inclinada lejos de la ventana. Una cosa es esperar que un código se ejecuta una vez (de lo contrario no hay ningún error o preguntas), pero una historia diferente para predecir o asumir desconoce la lógica de la aplicación. Y que me llame terco 😉 Muy exigente en su la la expresión sea correcta en mi humilde opinión. No en cualquier otra etiqueta, pero esta pregunta está etiquetada con javascript. Feliz navidad.
    • OMG, bueno, me disculpo por hacer un uso indebido «global» de la palabra. 🙂 No voy a pedir disculpas por llamar obstinada, aunque. 🙂 Feliz Navidad!
    • -1. El promises.push en b() es demasiado tarde, $.when() no cuenta para ellos.

  3. 2

    La pregunta puede ser viejo, pero ya no hay solución correcta, sin embargo, yo voy a poner aquí una respuesta. Correctamente las cadenas de las promesas mediante .a continuación, (precedentemente sido .pipe) para lograr el resultado solicitado:

    function a() {
      return $.ajax("http://url1").done(function(data){
        console.log('a called');
      }).then(function(){
        return $.when(b(), b()); //no loop for simplicity
      });
    }
    function b() {
      return $.ajax("http://url2").done(function(data){
        console.log('b called');
      });
    }
    
    function main(){
      a().done(function(){
        console.log('all completed');
      }, function() {
        console.log('an error occured!');
      });
    }

    Dependiendo del resultado de los datos deben estar disponibles en el lugar de anidación/estructura puede ser cambiado, pero el orden es correcto.

  4. 1

    Creo que esto puede ser solucionado con las devoluciones de llamada, pero un violín habría que realmente me ayudó a comprobar por ti.

     //called by main()
     function a(callback) {
       //set this to the number of loops that is going to happen
       var number = 2;
       return $.ajax("http://url1", function(data){
         console.log('a called');
         for (var i = 0; i < number ; i++) {
           b();
           if(number===i){
               callback();
           }
         }
       }
     }
    
     function main(){
        a(function(){
           //Function or code you want to run on completion.. 
        });
     }

    Perdóname si esto no funciona, pero creo que es la dirección correcta.

    • Aquí un violín de esta solución: jsfiddle.net/pxVAE/1. No acaba de funcionar, podría ser en mi transcribir…

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea