Como sempre executar algum código quando uma promessa é cumprida em Angular.js


83

Em meu aplicativo Angular.js, estou executando algumas operações assíncronas. Antes de começar, abordo o aplicativo com um div modal e, depois que a operação for concluída, preciso remover o div, quer a operação tenha sido bem-sucedida ou não.

Atualmente eu tenho este:

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

Funciona bem, mas prefiro algo mais limpo como este pseudo-código:

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

Presumo que seja um problema bastante comum, por isso pensei que poderia ser feito, mas não consigo encontrar nada no documento. Alguma ideia se isso pode ser feito?


Se você pode uma cadeia then(), então você certamente pode encadear outra ... .initialize().then(...).then(...). Não existe "finalmente" como tal; o manipulador final é o último especificado.
Beetroot-Beetroot

2
@ Beetroot-Beetroot, isso não funcionará porque se initialize()falhar, você ainda precisa declarar uma função de "sucesso" e uma função de "falha" e duplicar o código lá.
laurent de

Não vai funcionar, ou apenas deselegante?
Beetroot-Beetroot

1
Laurent, o que você deseja não está disponível no serviço $ q leve do Angular, que oferece promessas com apenas um método .then()- consulte "A API de promessa" aqui . A única liberdade é ter um .then()ou encadear vários .then()s. Você não é o primeiro a desejar uma API de promessa mais abrangente - o recurso que deseja é formalmente solicitado aqui .
Beetroot-Beetroot

1
Aparentemente, always(callback)não é implementado ou revertido no angular 1.2.6. Temos que usar finallyagora. Eu me pergunto por que a palavra reservada finallyé melhor do que always.
Aleyna

Respostas:


164

O recurso foi implementado nesta solicitação pull e agora faz parte do AngularJS. Ele foi inicialmente chamado de "sempre" e depois renomeado para finally, portanto, o código deve ser o seguinte:

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

Observe que, por finallyser uma palavra-chave reservada, pode ser necessário transformá-la em uma string para que não quebre em certos navegadores (como o IE e o Android):

$http.get('/foo')['finally'](doSomething);

10
Para qualquer um que encontrar isso em uma pesquisa na web, o link na resposta se refere à função, alwaysmas foi alterado para finallycomo você pode ver neste commit (ou na fonte): github.com/angular/angular.js/commit/…
Austin Thompson

@AustinThompson, obrigado pela informação, atualizei o post.
Laurent

@ this.lau_ o finally () tem que ser a última chamada na corrente, ou posso acorrentar mais do que () está fora dele?
Brian

2
Você senhor, fez o meu dia!
JacobF de

4
@Brian finallyretorna uma promessa como o resto, então você pode encadear. No entanto (pelo menos em algumas versões do Angular) a conveniência sobrecarrega successe errorsó são adicionadas ao retorno imediato de $http, portanto, se você começar com, finallyperderá esses métodos.
drzaus

7

Estou usando o back-end do Umbraco versão 7.3.5 com AngularJS versão 1.1.5 e encontrei este tópico. Quando implementei a resposta aprovada, obtive o erro:

xxx (...). então (...). finalmente não é uma função

O que funcionou, entretanto, foi always. Se alguém mais usando uma versão antiga do AngularJS encontrar este tópico e não puder usar, finallyuse este código

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

2

Para aqueles que não usam angularJS, e se você não tem problemas em detectar o erro (não tenho certeza se .finally () faria isso), você poderia usar .catch (). Then () para evitar o código duplicado.

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

O catch () pode acabar sendo útil de qualquer maneira para registro ou outra limpeza. https://jsfiddle.net/pointzerotwo/k4rb41a7/


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.