Как всегда запускать код при выполнении обещания в Angular.js

83

В моем приложении Angular.js я выполняю асинхронную операцию. Перед запуском я накрываю приложение модальным div, а затем, когда операция завершена, мне нужно удалить div, независимо от того, была ли операция успешной или нет.

В настоящее время у меня есть это:

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

Он работает хорошо, однако я бы предпочел иметь что-то более чистое, например этот псевдокод:

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

Я предполагаю, что это довольно распространенная проблема, поэтому я думал, что это можно сделать, но ничего не нашел в документе. Есть идеи, можно ли это сделать?

Лоран
источник
Если вы можете цепи один then(), то вы можете , конечно , цепь другого ... .initialize().then(...).then(...). Нет никакого «наконец» как такового; последний обработчик указан последним.
Beetroot-Beetroot
2
@ Beetroot-Beetroot, это не сработает, потому что в случае initialize()неудачи вам все равно нужно объявить как функцию «успеха», так и функцию «сбой», а также дублировать код.
laurent
Не получится или просто неэлегантно?
Beetroot-Beetroot
1
Лоран, то, что вы хотите, в настоящее время недоступно в облегченном сервисе $ q Angular, который предоставляет обещания только с одним методом, .then()- см. «API обещаний» здесь . Единственная свобода - иметь один .then()или объединять несколько .then()s. Вы не первый, кто желает иметь более обширный API обещаний - здесь официально запрашивается желаемая функция .
Beetroot-Beetroot
1
Видимо always(callback)не реализовано или откатано в angular 1.2.6. Надо использовать finallyсейчас. Интересно, почему зарезервированное слово finallyлучше чем always.
Алейна

Ответы:

164

Эта функция была реализована в этом запросе на перенос и теперь является частью AngularJS. Первоначально он назывался «всегда», а затем переименован в finally, поэтому код должен быть следующим:

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

Обратите внимание, что, поскольку finallyэто зарезервированное ключевое слово, может потребоваться сделать его строкой, чтобы она не ломалась в определенных браузерах (например, IE и браузере Android):

$http.get('/foo')['finally'](doSomething);
Лоран
источник
10
Для тех, кто нашел это в веб-поиске, ссылка в ответе относится к функции, alwaysно она была изменена на, finallyкак вы можете видеть в этом коммите (или в источнике): github.com/angular/angular.js/commit/…
Остин Томпсон
@AustinThompson, спасибо за информацию, я обновил пост.
laurent
@ this.lau_ должен ли finally () быть последним вызовом в цепочке, или я могу связать с ним еще () s?
Брайан
2
Вы, сэр, сделали мой день!
JacobF
4
@Brian finallyвозвращает обещание, как и все остальные, так что вы можете связать его. Однако (по крайней мере, в некоторых версиях Angular) удобство перегружается successи errorдобавляется только к немедленному возврату $http, поэтому, если вы начнете с, finallyвы потеряете эти методы.
drzaus
7

Я использую серверную часть Umbraco версии 7.3.5 с AngularJS версии 1.1.5 и нашел эту ветку. Когда я реализовал утвержденный ответ, я получил ошибку:

xxx (...). then (...). finally не является функцией

Однако то, что работало, было always. Если кто-то другой, использующий старую версию AngularJS, найдет этот поток и не может finallyиспользовать этот код вместо этого

LoadingOverlay.start(); 
Auth.initialize().then(function() {
    // Success handler
}, function() {
    // Error handler
}).always(function() {
    // Always execute this on both error and success
});
Огглас
источник
2

Для тех, кто не использует angularJS, и если у вас все в порядке с обнаружением ошибки (не уверен, что .finally () сделает это), вы можете использовать .catch (). Then (), чтобы избежать дублирования кода.

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

В любом случае catch () может оказаться полезным для ведения журнала или другой очистки. https://jsfiddle.net/pointzerotwo/k4rb41a7/

PointZeroTwo
источник