2011-06-06 19 views
6

Al utilizar jQuery diferidos y $.when para cargar muchos objetos en paralelo.jquery falla de giro diferido en éxito

$.when(
    a.ajax(), b.ajax(), c.ajax() 
).then(
    //do something when all are complete 
    complete(); 
); 

Ahora, se b.ajax() veces no, pero yo no realmente importa. Solo quiero esperar hasta que todas las llamadas se hayan completado antes de llamar a complete().

Lamentablemente, tan pronto como b falla, el when() rechaza y nunca desencadena la devolución de llamada then(). Este es el comportamiento esperado de AFAIK para $.when(), pero dosent me corresponde en este caso.

que efectivamente quieren una manera de decir:

$.when(
    a.ajax(), b.ajax().fail(return success), c.ajax() 
).then(...) 

O quizás hay una manera diferente de usar when(), o una construcción más adecuada?

+0

@Ates Creo que su respuesta eliminada puede solucionarse simplemente resolviendo ese nuevo objeto diferido antes de volver. – Alnitak

+0

posible duplicado de [$. Diferido: cómo detectar cuándo se ha ejecutado cada promesa] (http://stackoverflow.com/q/19177087/1048572) – Bergi

Respuesta

1

Así que lo he descubierto, al final, ver mi respuesta a otra persona con el mismo problema:

how to fool jqXHR to succeed always

La respuesta de lonesomeday fue ordenada, pero no del todo lo que buscaba.

+0

A partir de jQuery 1.8, la tubería está en desuso. Consulte la descripción en [jQuery Deferred luego] (https://api.jquery.com/deferred.then/). – Griffin

1

Se puede construir $.onFailSucceed con bastante facilidad envolviendo la $.Deferred objeto:

$.onCompleteSucceed = function(oldDfd) { 
    var newDfd = $.Deferred(); 

    oldDfd.always(newDfd.resolve); 

    return newDfd.promise(); 
} 

A continuación, podría envolver las llamadas apropiadas en este método:

$.when(
    a.ajax(), $.onCompleteSucceed(b.ajax()), c.ajax() 
).then(...) 
+0

buena solución, excepto que no pasará el resultado de 'b .ajax() 'en el controlador' .then() '. – Alnitak

3

Aquí hay algo mejor que hackear una falla en un éxito.

Hecho poco conocido, $ .when() ejecutará la devolución de llamada then() inmediatamente si falla alguno de los parámetros. Es por diseño. Para citar la documentación:

http://api.jquery.com/jQuery.when/

En el caso-Deferreds múltiples, donde se rechaza una de las Deferreds, jQuery.when se activa inmediatamente los failCallbacks para su amo Diferido. Tenga en cuenta que algunos de los aplazados aún no se han resuelto en ese momento. Si necesita realizar un procesamiento adicional para este caso, como cancelar cualquier solicitud ajax sin terminar, puede mantener referencias a los objetos jqXHR subyacentes en un cierre e inspeccionarlos/cancelarlos en failCallback.

En realidad, no hay una forma integrada de esperar hasta que todos ellos estén terminados independientemente de su estado de éxito/falla.

Entonces, construí $.whenAll() para ti :) Siempre espera hasta que todos ellos se resuelven, de un modo u otro:

http://jsfiddle.net/InfinitiesLoop/yQsYK/

+1

Gracias por esto. – tomswift

5

Si desea capturar el fracaso de una promesa y convertir eso a un éxito, se puede utilizar el failFilter de then para devolver una promesa resuelta, así:

deferredCall.then(function(answer) { 
    // this is success. you might transform the answer here. 
    return transformed; 
}, function() { 
    // this is a fail. you might resolve the fail with an empty object. 
    return $.Deferred().resolve({}).promise(); 
}); 

Hacer esto se asegurará de que la cadena puede continuar más allá de la falta ininterrumpida.

Así que, por su ejemplo, es posible hacer esto:

$.when([ 
    a.ajax(), 
    b.ajax().then(function(answer) { 
     return answer; 
    }, function() { 
     return $.Deferred().resolve({}).promise(); 
    }), 
    c.ajax() 
]).then(function(results) { 
    // etc. 
}); 

Ejemplo 2: En mis aplicaciones, a veces uso then para obtener datos relacionales para una entidad particular y permitir la posibilidad de un 404 a indican que no existe tal relación:

getEntity(id).then(function(entity) { 
    return getAssociation(id).then(function(association) { 
     entity.association = association; 
     return entity; 
    }, function() { 
     entity.association = null; 
     return $.Deferred().resolve(entity).promise(); 
    }); 
}).done(function(entity) { 
    // etc. 
}); 

Nota, respuestas más antiguas sugieren usando el método pipe. Este método está en desuso a partir de jQuery 1.8.

+0

¿Alguna idea de por qué esto no funciona? Lo intenté y todavía va al caso de falla en la tubería – Andrey

+0

Es importante que su controlador de fallas (la segunda función de "luego") devuelva una promesa resuelta. Una promesa fallida o cualquier valor, no una promesa, permitirá que la cadena continúe hasta otro manejador de errores. – Griffin

Cuestiones relacionadas