Cómo ejecutar siempre algún código cuando se cumple una promesa en Angular.js

83

En mi aplicación Angular.js, estoy ejecutando una operación asincrónica. Antes de que comience, cubro la aplicación con un div modal, luego, una vez que se completa la operación, necesito eliminar el div, ya sea que la operación haya sido exitosa o no.

Actualmente tengo esto:

LoadingOverlay.start(); 
Auth.initialize().then(function() {
    LoadingOverlay.stop();
}, function() {
    LoadingOverlay.stop(); // Code needs to be duplicated here
})

Funciona bien, sin embargo, preferiría tener algo más limpio como este pseudocódigo:

LoadingOverlay.start(); 
Auth.initialize().finally(function() { // *pseudo-code* - some function that is always executed on both failure and success.
    LoadingOverlay.stop();
})

Supongo que es un problema bastante común, así que estaba pensando que se podría hacer pero no puedo encontrar nada en el documento. ¿Alguna idea de si se puede hacer?

Laurent
fuente
Si puede una cadena then(), entonces seguramente puede encadenar otra ... .initialize().then(...).then(...). No existe un "finalmente" como tal; el controlador final es el último especificado.
Remolacha-Remolacha
2
@ Beetroot-Beetroot, eso no funcionará porque si initialize()falla, aún necesita declarar una función de "éxito" y una función de "falla" y el código duplicado allí.
Laurent
¿No funcionará o simplemente no será elegante?
Remolacha-Remolacha
1
Laurent, lo que desea no está disponible actualmente en el servicio ligero $ q de Angular, que proporciona promesas con un solo método, .then()consulte "La API de promesa" aquí . La única libertad es tener uno .then()o encadenar varios .then()s. No es el primero en desear una API de promesa más extensa: la función que desea se solicita formalmente aquí .
Remolacha-Remolacha
1
Aparentemente always(callback)no está implementado o revertido en angular 1.2.6. Tenemos que usar finallyahora. Me pregunto por qué la palabra reservada finallyes mejor que always.
Aleyna

Respuestas:

164

La función se implementó en esta solicitud de extracción y ahora es parte de AngularJS. Inicialmente se llamó "siempre" y luego se le cambió el nombre a finally, por lo que el código debería ser el siguiente:

LoadingOverlay.start(); 
Auth.initialize().then(function() {
    // Success handler
}, function() {
    // Error handler
}).finally(function() {
    // Always execute this on both error and success
});

Tenga en cuenta que, dado que finallyes una palabra clave reservada, podría ser necesario convertirla en una cadena para que no se rompa en ciertos navegadores (como IE y el navegador de Android):

$http.get('/foo')['finally'](doSomething);
Laurent
fuente
10
Para cualquiera que encuentre esto en una búsqueda web, el enlace en la respuesta se refería a la función, alwayspero se cambió a finallycomo puede ver en esta confirmación (o en la fuente): github.com/angular/angular.js/commit/…
Austin Thompson
@AustinThompson, gracias por la información, he actualizado la publicación.
Laurent
@ this.lau_ ¿tiene que finalmente () ser la última llamada en la cadena, o puedo encadenar más de () s fuera de ella?
Brian
2
¡Señor, me alegró el día!
JacobF
4
@Brian finallydevuelve una promesa como el resto, para que puedas encadenarla. Sin embargo (al menos en algunas versiones de Angular) la conveniencia se sobrecarga successy errorsolo se agrega al retorno inmediato de $http, por lo que si comienza con finally, perderá esos métodos.
drzaus
7

Estoy usando el back-end de la versión 7.3.5 de Umbraco con la versión 1.1.5 de AngularJS y encontré este hilo. Cuando implementé la respuesta aprobada, recibí el error:

xxx (...). entonces (...). finalmente no es una función

Sin embargo, lo que funcionó fue always. Si alguien más que usa una versión anterior de AngularJS encuentra este hilo y no puede finallyusar este código en su lugar

LoadingOverlay.start(); 
Auth.initialize().then(function() {
    // Success handler
}, function() {
    // Error handler
}).always(function() {
    // Always execute this on both error and success
});
Ogglas
fuente
2

Para aquellos que no usan angularJS, y si está de acuerdo con detectar el error (no estoy seguro de si .finally () haría eso), podría usar .catch (). Then () para evitar el código duplicado.

Promise.resolve()
  .catch(() => {})
  .then(() => console.log('finally'));

El catch () podría terminar siendo útil de todos modos para el registro u otra limpieza. https://jsfiddle.net/pointzerotwo/k4rb41a7/

PointZeroTwo
fuente