jQuery ajax órdenes de callback diferidas

No puedo obtener las devoluciones de llamada hechas / falladas / siempre en cada una de mis solicitudes ajax para ejecutar antes de las devoluciones de llamada del objeto diferido.

El problema que tengo es que algunas de mis solicitudes de ajax pueden fallar, pero necesito ejecutar el mismo código si una falla o ninguna falla.

Es difícil de explicar exactamente, así que hice este violín para ayudar a mostrar el problema que tengo. http://jsfiddle.net/zZsxV/

var a1 = $.Deferred(); var a2 = $.Deferred(); var a3 = $.Deferred(); a1.done(function() { $('body').append('a1 done
'); }).fail(function() { $('body').append('a1 fail
'); }).always(function() { $('body').append('a1 always
'); }); a2.done(function() { $('body').append('a2 done
'); }).fail(function() { $('body').append('a2 fail
'); }).always(function() { $('body').append('a2 always
'); }); a3.done(function() { $('body').append('a3 done
'); }).fail(function() { $('body').append('a3 fail
'); }).always(function() { $('body').append('a3 always
'); }); var def = $.when(a1, a2, a3); def.always(function() { $('body').append('defer always <-- should be after all
'); }); setTimeout(function() { a1.resolve(); }, 5000); setTimeout(function() { a2.reject(); }, 1000); setTimeout(function() { a3.resolve(); }, 3000);

Leí muchas de las respuestas sobre este tema, pero no creo que ninguna se ajuste exactamente a mi necesidad.

Cualquier otra información necesaria para ayudar, por favor avíseme y la agregaré una vez que regrese. Gracias por adelantado.


Editar

Entiendo lo que está pasando. Sólo sé cómo hacerlo para evitar este problema. Intenté usar .then también con los mismos resultados. Una vez que se rechaza una solicitud, activa la callback fallida antes de esperar a las otras devoluciones de llamada.

De acuerdo con la documentación de jQuery, $.when devoluciones de llamada cuando se resuelven todos los parámetros o se rechaza uno de ellos. Entonces, ¿qué hay de usar algo así en lugar de $.when ?

 var custom_when = function() { var args = $.makeArray(arguments); var callback = args.pop(); var all = []; $.each(args, function(index, def) { def.always(function() { var idx = all.indexOf(def); if (idx !== -1) { all.splice(idx, 1); } if (!all.length) { callback(); } }); all.push(def); }); }; 

y puedes usarlo así:

 custom_when(a1, a2, a3, function() { // do some stuff. }); 

y jsFiddle demo .

Veo lo que intentas hacer aquí, pero no hay un método conveniente. Esto funciona:

JSFIDDLE

 $.when(a1).done(a2).done(a3).then(function() { $('body').append('defer always <-- should be after all
'); });

Otra opción sería escribir tu propia función simple. Ver FIDDLE actualizado:

 whenAllResolved(a1, a2, a3).done(function () { $('body').append('defer always <-- should be after all
'); }); function whenAllResolved(){ var d = $.Deferred(), args = arguments, verifyDeferreds = function(){ var allResolved = true; $.each(args, function(i, arg){ if(arg.state() === 'pending'){ allResolved = false; return false; } }); if (allResolved){ d.resolve(); } }; $.each(arguments, function(i, arg){ arg.always(verifyDeferreds); }); verifyDeferreds(); return d; }

Oye, tuve un problema similar a esto, no tengo el código conmigo, pero intentaré encontrarlo.

De todos modos, lo que hice fue tener una variable con la cantidad de objetos que necesitaba esperar, y solo disminuirla cuando uno de ellos termine, y luego verificar si era 0 si puedo llamar a la otra función.