Як завжди запускати якийсь код, коли обіцянка виконується в 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(...). Немає "остаточно" як такого; кінцевий обробник - це останній вказаний.
Буряк-Буряк

2
@ Beetroot-Beetroot, це не спрацює, тому що в разі initialize()невдачі вам все одно потрібно оголосити як функцію "успіху", так і функцію "невдало" та дублікат коду.
Лоран,

Не вийде, чи просто неелегантно?
Буряк-Буряк

1
Лорене, те, що ти хочеш, наразі недоступне в легкій службі Angular $ q, яка забезпечує обіцянки лише одним методом, .then()- див. "The Promise API" тут . Єдина свобода - це мати один .then()або зв’язати кілька .then()s. Ви не перший бажаєте більш розширеного API обіцянок - функція, яку ви хочете, офіційно запитується тут .
Буряк-Буряк

1
Очевидно, always(callback)це не реалізовано або відкатано назад у кутовій версії 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 Browser):

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

10
Для тих, хто знайшов це за допомогою веб-пошуку, посилання у відповіді посилалося на функцію, alwaysале її було змінено на, finallyяк ви можете бачити у цьому коміті (або у джерелі): github.com/angular/angular.js/commit/…
Остін Томпсон,

@AustinThompson, дякую за інформацію, я оновив допис.
Лоран,

@ this.
Брайан

2
Ви, сер, зробили мені день!
JacobF

4
@Brian finallyповертає обіцянку, як і всі інші, так що ви можете прив'язати її. Однак (принаймні в деяких версіях Angular) зручність перевантажується successі errorдодається лише до негайного повернення $http, тому, якщо ви почнете з, finallyви втратите ці методи.
drzaus

7

Я використовую Umbraco версії 7.3.5 з кінцевою версією AngularJS версії 1.1.5 і знайшов цю тему. Коли я реалізував затверджену відповідь, я отримав помилку:

xxx (...). тоді (...). нарешті не є функцією

Що, однак, спрацювало 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/


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.