2011-11-08 9 views
11

Tengo una aplicación web que debe llamar al servidor varias veces. Hasta el momento, tenía una larga cadena de devolución de llamada anidada; pero me gustaría utilizar la funcionalidad when, then de jQuery. Sin embargo, parece que no puedo ejecutar nada nuevamente después de usar un then.Encadenamiento de solicitudes ajax con el diferido de jQuery

$ 
.when ($.get('pages/run-tool.html')) 
.then (function (args) 
{ 
    // This works fine 
    alert(args); 
    $('#content').replaceWith (args); 
    $('#progress-bar').progressbar ({value: 0}); 
}) 
.then ($.get('pages/test.html')) 
.done (function(args) 
{ 
    // This prints the same as the last call 
    alert (args); 
}); 

¿Qué estoy haciendo mal? Supongo que es un problema de alcance, ya que puedo ver que se está ejecutando la segunda llamada get. El uso de dos variables diferentes args no ayuda, ya que el argumento pasado a la función completada sigue siendo la primera solicitud get.

Respuesta

29

Como una actualización:

con jQuery moderna (1.8+) que no es necesario el previo cuando porque obtener devuelve una promesa diferido.

También, la tubería está obsoleta. Use luego en su lugar. Solo asegúrese de devolver el resultado de la nueva obtención que se convierte en la Promesa adjuntada por las siguientes/* done */llamadas fallidas.

Así:

$.get('pages/run-tool.html') 
.then (function (args) { // this will run if the above .get succeeds 
    // This works fine 
    alert(args); 
    $('#content').replaceWith (args); 
    $('#progress-bar').progressbar ({value: 0}); 
}) 
.then (function() { // this will run after the above then-handler (assuming it ran) 
    return $.get('pages/test.html'); // the return value creates a new Deferred object 
}) 
.done (function(args) { // this will run after the second .get succeeds (assuming it ran) 
    alert (args); 
}); 
12

Las tres devoluciones de llamada (las dos con then y la que tiene done) se aplican a la misma solicitud: la llamada original when. Esto se debe a que then devuelve el mismo objeto diferido, en lugar de uno nuevo, para que pueda agregar varios controladores de eventos.

En su lugar, necesita usar pipe.

$ 
.when ($.get('pages/run-tool.html')) 
.then (function (args) 
{ 
    // This works fine 
    alert(args); 
    $('#content').replaceWith (args); 
    $('#progress-bar').progressbar ({value: 0}); 
}) 
.pipe (function() { 
    return $.get('pages/test.html'); // the return value creates a new Deferred object 
}) 
.done (function(args) 
{ 
    alert (args); 
}); 
+0

¡Gracias, eso funciona! Lo aceptaré tan pronto como stackoverflow me permita :) – Anteru

+0

jQuery encadenar todavía se ve horrible para mí – PHearst

+1

@PHearst Tenga en cuenta que este método ahora está en desuso. – lonesomeday

-2

Mi manera es aplicar la función de devolución de llamada:

A(function(){ 
     B(function(){ 
      C()})}); 

donde A, B se puede escribir como

function A(callback) 
$.ajax{ 
    ... 
    success: function(result){ 
     ... 
     if (callback) callback(); 
    } 
} 
+3

Sin embargo, esto no usa el aplazamiento de jQuery, y es propenso al "efecto de pirámide" (la anidación no acotada causa una sangría fuerte). Supongo que esto es lo que el asker trató de evitar. –

1

Aquí es un maravillosamente simple y altamente efectivo encadenamiento/cola de AJAX. Te ejecutará métodos ajax en secuencia uno después del otro.

Funciona al aceptar una matriz de métodos y luego ejecutarlos en secuencia. No ejecutará el siguiente método mientras espera una respuesta.

// --- ESTA PARTE ES SU CÓDIGO -----------------------

$ (document). listo (función() {

var AjaxQ = []; 
AjaxQ[0] = function() { AjaxMethod1(); } 
AjaxQ[1] = function() { AjaxMethod2(); } 
AjaxQ[3] = function() { AjaxMethod3(); } 

//Execute methods in sequence 
$(document).sc_ExecuteAjaxQ({ fx: AjaxQ }); 

});

// --- Esta parte es el plugin AJAX -------------------

$ .fn.sc_ExecuteAjaxQ = function (opciones) {

//? Executes a series of AJAX methods in dequence 

var options = $.extend({ 

    fx: [] //function1() { }, function2() { }, function3() { } 

}, options); 

if (options.fx.length > 0) { 

    var i = 0; 

    $(this).unbind('ajaxComplete'); 
    $(this).ajaxComplete(function() { 

     i++; 
     if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); } 
     else { $(this).unbind('ajaxComplete'); } 

    }); 

    //Execute first item in queue 
    if (typeof options.fx[i] == "function") { options.fx[i](); } 
    else { $(this).unbind('ajaxComplete'); } 

} 

}

0
<script type="text/javascript"> 

    var promise1 = function() { 
     return new 
     $.Deferred(function (def) { 
      setTimeout(function() { 
       console.log("1"); 
       def.resolve(); 
      }, 3000); 
     }).promise(); 
    }; 

    var promise2 = function() { 
     return new 
     $.Deferred(function (def) { 
      setTimeout(function() { 
       console.log("2"); 
       def.resolve(); 
      }, 2000); 
     }).promise(); 
    }; 

    var promise3 = function() { 
     return new 
     $.Deferred(function (def) { 
      setTimeout(function() { 
       console.log("3"); 
       def.resolve(); 
      }, 1000); 
     }).promise(); 
    }; 

    var firstCall = function() { 
     console.log("firstCall"); 
     $.when(promise1()) 
     .then(function() { secondCall(); }); 
    }; 

    var secondCall = function() { 
     console.log("secondCall") 
     $.when(promise2()).then(function() { thirdCall(); }); 
    }; 

    var thirdCall = function() { 
     console.log("thirdCall") 
     $.when(promise3()).then(function() { console.log("done"); }); 
    }; 


    $(document).ready(function() { 
     firstCall(); 
    }); 
</script> 
0

pensé que iba a salir de este pequeño ejercicio aquí para cualquier persona que les puede resultar útil, construimos una serie de peticiones y cuando se han completado, se puede disparar una función de devolución de llamada:

var urls = [{ 
    url: 'url1', 
    data: 'foo' 
}, { 
    url: 'url2', 
    data: 'foo' 
}, { 
    url: 'url3', 
    data: 'foo' 
}, { 
    url: 'url4', 
    data: 'foo' 
}]; 
var requests = []; 
var callback = function (result) { 
    console.log('done!'); 
}; 

var ajaxFunction = function() { 
    for (var request, i = -1; request = urls[++i];) { 
     requests.push($.ajax({ 
      url: request.url, 
      success: function (response) { 
       console.log('success', response); 
      } 
     })); 
    } 
}; 

// using $.when.apply() we can execute a function when all the requests 
// in the array have completed 
$.when.apply(new ajaxFunction(), requests).done(function (result) { 
    callback(result) 
}); 
1

el CDR respuesta dio, que tiene el mayor número de votos por el momento, no está bien.

Cuando tenga funciones a, b, c de cada devuelve un objeto $ .Deferred(), y las cadenas de las funciones como las siguientes:

a().then(b).then(c) 

byc se ejecutará una vez que la promesa de regresar de una esta resuelto. Dado que tanto entonces() funciones están vinculadas a la promesa de una, esto funciona similar a otra Jquery encadenar tales como:

$('#id').html("<div>hello</div>").css({display:"block"}) 

donde tanto html() y la función css() se llaman en el objeto devuelto por $ ('#carné de identidad');

Así que para hacer a, b, ejecución de C después de la promesa de regresar de la función anterior se resuelve, lo que necesita hacer esto:

a().then(function(){ 
    b().then(c) 
}); 

Aquí la llamada de la función C está ligado a la promesa de regresar de función b.

Esto se comprueba mediante el siguiente código:

function a() { 
    var promise = $.Deferred(); 
    setTimeout(function() { 
     promise.resolve(); 
     console.log("a"); 
    }, 1000); 
    return promise; 
} 

function b() { 
    console.log("running b"); 
    var promise = $.Deferred(); 
    setTimeout(function() { 
     promise.resolve(); 
     console.log("b"); 
    }, 500); 
    return promise; 
} 

function c() { 
    console.log("running c"); 
    var promise = $.Deferred(); 
    setTimeout(function() { 
     promise.resolve(); 
     console.log("c"); 
    }, 1500); 
    return promise; 
} 

a().then(b).then(c); 
a().then(function(){ 
    b().then(c) 
}); 

cambio de la promesa de la función b() de determinación() para rechazar() y verá la diferencia.

+0

cdr answer is right. Compruebe este violín http://jsfiddle.net/0pb0g70y/ hecho con su código, con algunos cambios para mayor claridad. 'c' no se llama hasta que' b' finaliza. El segundo 'entonces' no se aplica a la promesa' a', sino a la promesa devuelta por 'b' (si devuelve una promesa, que es el caso en su ejemplo, y en la respuesta cdr para su segundo' entonces') . –

Cuestiones relacionadas