So führen Sie immer Code aus, wenn ein Versprechen in Angular.js erfüllt ist

83

In meiner Angular.js-Anwendung führe ich eine asynchrone Operation aus. Bevor es beginnt, bedecke ich die Anwendung mit einem modalen Div. Sobald der Vorgang abgeschlossen ist, muss ich den Div entfernen, unabhängig davon, ob der Vorgang erfolgreich war oder nicht.

Derzeit habe ich Folgendes:

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

Es funktioniert gut, aber ich hätte lieber etwas saubereres wie diesen Pseudocode:

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

Ich gehe davon aus, dass es ein weit verbreitetes Problem ist, also dachte ich, es könnte getan werden, kann aber nichts im Dokument finden. Irgendeine Idee, ob es möglich ist?

Laurent
quelle
Wenn Sie Ketten man kann then(), dann können Sie sicher Kette eine andere ... .initialize().then(...).then(...). Es gibt kein "endlich" als solches; Der letzte Handler ist der zuletzt angegebene.
Rote Beete-Rote Beete
2
@ Beetroot-Beetroot, das wird nicht funktionieren, denn wenn dies initialize()fehlschlägt, müssen Sie immer noch sowohl eine "Erfolgs" -Funktion als auch eine "Fehler" -Funktion deklarieren und dort Code duplizieren.
Laurent
Wird nicht funktionieren oder nur unelegant?
Rote Beete-Rote Beete
1
Laurent, was Sie wollen, ist derzeit nicht in Angulars leichtem $ q-Service verfügbar, der Versprechen mit nur einer Methode bietet .then()- siehe "The Promise API" hier . Die einzige Freiheit besteht darin, eine zu haben .then()oder mehrere .then()s zu verketten . Sie sind nicht der erste, der sich eine umfassendere Versprechen-API wünscht - die gewünschte Funktion wird hier offiziell angefordert .
Rote Beete-Rote Beete
1
Anscheinend always(callback)wird in Winkel 1.2.6 nicht implementiert oder zurückgesetzt. Wir müssen finallyjetzt verwenden. Ich frage mich, warum das reservierte Wort finallybesser ist als always.
Aleyna

Antworten:

164

Die Funktion wurde in dieser Pull-Anforderung implementiert und ist jetzt Teil von AngularJS. Es wurde ursprünglich "immer" genannt und später in "umbenannt" finally, daher sollte der Code wie folgt lauten:

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

Da finallyes sich um ein reserviertes Schlüsselwort handelt, muss es möglicherweise als Zeichenfolge festgelegt werden, damit es in bestimmten Browsern (z. B. IE und Android Browser) nicht beschädigt wird:

$http.get('/foo')['finally'](doSomething);
Laurent
quelle
10
Für alle, die dies über eine Websuche finden, bezieht sich der Link in der Antwort auf die Funktion always, wurde jedoch geändert, finallywie Sie in diesem Commit (oder in der Quelle) sehen können: github.com/angular/angular.js/commit/…
Austin Thompson
@AustinThompson, danke für die Information, ich habe den Beitrag aktualisiert.
Laurent
@ this.lau_ Muss das finally () der letzte Aufruf in der Kette sein, oder kann ich mehr verketten, als () davon abweicht?
Brian
2
Sie, mein Herr, haben meinen Tag gemacht!
Jvannistelrooy
4
@Brian finallygibt wie der Rest ein Versprechen zurück, sodass Sie es verketten können. Jedoch (zumindest auf einigen Versionen von Angular) der Bequemlichkeit Überlastungen successund errorsind nur auf die unmittelbare Rückkehr von hinzugefügt $http, so dass , wenn Sie beginnen mit finallyIhnen diese Methoden verlieren.
Drzaus
7

Ich verwende Umbraco Version 7.3.5 Backend mit AngularJS Version 1.1.5 und habe diesen Thread gefunden. Als ich die genehmigte Antwort implementierte, bekam ich den Fehler:

xxx (...). dann (...). ist endlich keine Funktion

Was jedoch funktionierte, war always. Wenn jemand, der eine alte Version von AngularJS verwendet, diesen Thread findet und finallydiesen Code nicht verwenden kann, verwenden Sie ihn stattdessen

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

Wenn Sie angularJS nicht verwenden und den Fehler nicht abfangen können (nicht sicher, ob .finally () dies tun würde), können Sie .catch (). Then () verwenden, um den duplizierten Code zu vermeiden.

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

Der catch () kann ohnehin für die Protokollierung oder andere Bereinigung nützlich sein. https://jsfiddle.net/pointzerotwo/k4rb41a7/

PointZeroTwo
quelle