Jak zawsze uruchamiać kod, gdy obietnica jest spełniona w Angular.js.

83

W mojej aplikacji Angular.js wykonuję operację asynchroniczną. Zanim się zacznie, zakrywam aplikację modalnym divem, a po zakończeniu operacji muszę usunąć div, niezależnie od tego, czy operacja się powiodła, czy nie.

Obecnie mam to:

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

Działa dobrze, ale wolałbym mieć coś czystszego, takiego jak ten pseudokod:

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

Zakładam, że to dość powszechny problem, więc myślałem, że można to zrobić, ale nie mogę znaleźć niczego w dokumencie. Masz jakiś pomysł, czy można to zrobić?

laurent
źródło
Jeśli można jeden łańcuch then(), a następnie można z pewnością przykuje inny ... .initialize().then(...).then(...). Nie ma „wreszcie” jako takiego; ostatni program obsługi to ostatni określony.
Burak-Burak
2
@ Beetroot-Beetroot, to nie zadziała, ponieważ jeśli initialize()zawiedzie, nadal musisz zadeklarować zarówno funkcję „sukcesu”, jak i funkcję „fail” i zduplikowany kod.
laurent
Nie zadziała, czy po prostu nieeleganckie?
Burak-Burak
1
Laurent, to, czego chcesz, nie jest obecnie dostępne w lekkiej usłudze $ q firmy Angular, która zapewnia obietnice za pomocą tylko jednej metody .then()- zobacz „The Promise API” tutaj . Jedyną swobodą jest posiadanie jednego .then()lub łączenie wielu .then()s. Nie jesteś pierwszą osobą, która marzy o bardziej rozbudowanym interfejsie API obietnicy - żądana funkcja jest tutaj formalnie wymagana .
Burak-Burak
1
Najwyraźniej always(callback)nie jest zaimplementowany ani wycofany w kątowym 1.2.6. Musimy użyć finallyteraz. Zastanawiam się, dlaczego zarezerwowane słowo finallyjest lepsze niż always.
Aleyna

Odpowiedzi:

164

Ta funkcja została zaimplementowana w tym żądaniu ściągnięcia i jest teraz częścią AngularJS. Początkowo nazywano go „zawsze”, a później zmieniono na finally, więc kod powinien wyglądać następująco:

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

Zwróć uwagę, że ponieważ finallyjest to zarezerwowane słowo kluczowe, może być konieczne utworzenie ciągu, aby nie zepsuł się w niektórych przeglądarkach (takich jak IE i Android):

$http.get('/foo')['finally'](doSomething);
laurent
źródło
10
Dla każdego, kto znalazł to na podstawie wyszukiwania w Internecie, łącze w odpowiedzi odnosiło się do funkcji, alwaysale zostało zmienione na, finallyjak widać w tym zatwierdzeniu (lub w źródle): github.com/angular/angular.js/commit/ ...
Austin Thompson,
@AustinThompson, dzięki za informację, zaktualizowałem post.
laurent
@ this.lau_, czy last () musi być ostatnim wywołaniem w łańcuchu, czy mogę z niego połączyć więcej niż () s?
Brian
2
Panie, uczynił mój dzień!
JacobF
4
@Brian finallyzwraca obietnicę tak jak reszta, więc możesz ją połączyć . Jednak (przynajmniej w niektórych wersjach Angulara) wygoda jest przeciążona successi errorsą dodawane tylko do natychmiastowego powrotu $http, więc jeśli zaczniesz od finally, stracisz te metody.
drzaus
7

Używam zaplecza Umbraco w wersji 7.3.5 z AngularJS w wersji 1.1.5 i znalazłem ten wątek. Po zaimplementowaniu zatwierdzonej odpowiedzi otrzymałem błąd:

xxx (...). to (...). ostatecznie nie jest funkcją

Jednak to, co zadziałało always. Jeśli ktoś inny używający starej wersji AngularJS znajdzie ten wątek i nie może finallyużyć tego kodu

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

Dla tych, którzy nie używają angularJS i jeśli nie przeszkadza ci wychwycenie błędu (nie jesteś pewien, czy .finally () to zrobi), możesz użyć .catch (). Then (), aby uniknąć zduplikowanego kodu.

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

Metoda catch () może i tak okazać się przydatna do logowania lub innego czyszczenia. https://jsfiddle.net/pointzerotwo/k4rb41a7/

PointZeroTwo
źródło