sincronas promesas funciones encadenar encadenamiento asincronas anidadas javascript jquery asynchronous deferred

funciones - promesas javascript



¿Cómo puedo encadenar tres llamadas asincrónicas utilizando las promesas de jQuery? (10)

En cada caso, devuelva el objeto jqXHR devuelto por $.ajax() .

Estos objetos son compatibles con Promise, por lo que se pueden encadenar con .then() / .done() / .fail() / .always() .

.then() es el que desea en este caso, exactamente como en la pregunta.

function first() { return $.ajax(...); } function second(data, textStatus, jqXHR) { return $.ajax(...); } function third(data, textStatus, jqXHR) { return $.ajax(...); } function main() { first().then(second).then(third); }

Los data Argumentos, textStatus y jqXHR surgen de la llamada $.ajax() en la función anterior, es decir. first() alimenta el second() y el second() feeds third() .

DEMO (con $.when(''foo'') para entregar una promesa cumplida, en lugar de $.ajax(...) ).

Tengo tres llamadas HTTP que necesito hacer de forma síncrona y ¿cómo paso los datos de una llamada a la otra?

function first() { ajax() } function second() { ajax() } function third() { ajax() } function main() { first().then(second).then(third) }

Traté de usar el diferido para las dos funciones y se me ocurrió una solución parcial. ¿Puedo extenderlo para tres funciones?

function first() { var deferred = $.Deferred(); $.ajax({ "success": function (resp) { deferred.resolve(resp); }, }); return deferred.promise(); } function second(foo) { $.ajax({ "success": function (resp) { }, "error": function (resp) { } }); } first().then(function(foo){second(foo)})


En realidad, hay un enfoque mucho más fácil al usar promesas con jQuery. Eche un vistazo a lo siguiente:

$.when( $.ajax("/first/call"), $.ajax("/second/call"), $.ajax("/third/call") ) .done(function(first_call, second_call, third_call){ //do something }) .fail(function(){ //handle errors });

Simplemente encadena todas tus llamadas a la llamada $ .cuando (...) y gestiona los valores devueltos en la llamada .done (...).

Aquí hay un tutorial si lo prefiere: http://collaboradev.com/2014/01/27/understanding-javascript-promises-in-jquery/


Encontré una buena solución aquí: ¿Cómo encadenar una secuencia de funciones diferidas en jQuery 1.8.x?

Y aquí está mi propia implementación de un enfoque similar, algo feo pero probablemente funcione. Emite el resultado de cada método como una «actualización de progreso» en el objeto prometido devuelto.

$.chain = function() { var def = $.Deferred(); var funcs = arguments; var left = arguments.length; function next() { if(left == 0) { def.resolve(); return; } var func = funcs[funcs.length - left]; // current func var prom = func(ret).promise(); // for promise will return itself, // for jquery ojbect will return promise. // these handlers will be launched in order we specify them prom.always(function() { left--; }).done(function(ret) { def.notify({ idx: funcs.length-left, left: left, result: ret, success: true, }); }).fail(function(ret) { def.notify({ idx: funcs.length-left, left: left, result: ret, success: false, }); }).always(function(ret) { next(ret); }); } next(); return def.promise(); };

¿Cómo usarlo para su situación? Tal vez no es hermoso, pero debería funcionar:

function first() { return ajax(...); } var id; funciton second() { return ajax(id, ...); } function third() { return ajax(id, ...); } $.chain(first, second, third).progress(function(p) { if(p.func == first) id = p.result.identifier; }).then(function() { alert(''everything is done''); });

O simplemente puede asignar esa variable de identificación desde la first función.

O si solo necesita el resultado de la función anterior, puede usar este enfoque:

function first() { return ajax(...); } function second(first_ret) { return ajax(first_ret.id, ...); } function third(second_ret) { return ajax(second_ret.something, ...); }


Es bastante tarde para responder, pero creo que a las respuestas les falta un código directo para encadenar. Encadenar eventos es bastante simple con soporte de promesas en jquery. Uso lo siguiente para encadenar:

$.ajax() .then(function(){ return $.ajax() //second ajax call }) .then(function(){ return $.ajax() //third ajax call }) .done(function(resp){ //handle final response here })

Es simple, sin complicados bucles o múltiples devoluciones de llamada anidadas.


Es mucho más simple que eso.

$.ajax ya devuelve una promesa (objeto diferido), por lo que simplemente puede escribir

function first() { return $.ajax(...); }


La mejor manera de hacerlo es haciendo una función reutilizable para esto. Esto incluso se puede hacer con solo una línea de código usando reduce :

function chainPromises(list) { return list.reduce((chain, func) => chain ? chain.then(func) : func(), null); }

Esta función acepta una matriz de devoluciones de llamada que devuelve un objeto de promesa, como sus tres funciones.

Ejemplo de uso:

chainPromises([first, second, third]).then(function (result) { console.log(''All done! '', result); });

De esta forma, el resultado de first también será automáticamente el parámetro de second , así que básicamente lo que sucede es esto:

first().then(function(res1) { return second(res1) }) .then(function(res2) { return third(res2) }) .then(function(result) { console.log(''All done! '', result) });

Y, por supuesto, puede agregar tantas funciones a la matriz como desee.


Lo siguiente parece funcionar y permite que la lista de funciones sea dinámica:

<html> <head> <title>demo chained synchronous calls</title> </head> <body> <script src="http://code.jquery.com/jquery-2.2.4.min.js"></script> <script type="text/javascript"> function one(parms) { console.log(''func one '' + parms); return 1; } function two(parms) { console.log(''func two '' + parms); return 2; } function three(parms) { console.log(''func three '' + parms); return 3; } function four(parms) { console.log(''func four '' + parms); return 4; } var funcs = [''one'', ''two'', ''three'', ''four'']; var rvals = [0]; function call_next_func() { if (funcs.length == 0) { console.log(''done''); } else { var funcname = funcs.shift(); console.log(funcname); rvals.push(window[funcname](rvals)); call_next_func(); } } $(document).ready(function($){ call_next_func(); }); </script> </body> </html>


Para encadenar jquery ajax llamé:

function A(){ return $.ajax({ url: url, type: type, data: data, datatype: datatype, success: function(data) { code here } }); } function B(){ return $.ajax({ url: url, type: type, data: data, datatype: datatype, success: function(data) { code here } }); } function C(){ return $.ajax({ url: url, type: type, data: data, datatype: datatype, success: function(data) { code here } }); } A().done(function(data){ B().done(function(data){ C(); }) });


Puedes escribirlo de una manera más funcional:

[function() { return ajax(...)}, function(data) { return ajax(...)}] .reduce(function(chain, callback) { if(chain) { return chain.then(function(data) { return callback(data); }); } else { return callback(); } }, null)


Solo tuve el mismo problema, encadenando llamadas ajax. Después de unos días de intentarlo, finalmente hice $.ajax({ async: false,... qué hizo completamente lo que quería archivar. Simplemente no pensé en eso. Podría ayudar a otros ...