17

I observe that In angular 2 there is no finally block for promise API

angular 1 :

 loadUsers() {
  fetch('/api/users').then((response) => {
    return response.json();
  }).then((data) => {
    this.users = data;
  }).catch((ex) => {
    console.error('Error fetching users', ex);
  }).finally(() => {
     this.userLoaded = true;
};

Assuming I have to do same thing in angular 2

How to add finally block in angular 2 promise , as of now there are only then & catch blocks available in angular 2. If not finally then is there any way to add cleanup code after execution of each method , where do i write code to do finally block activities ?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Dmehro
  • 1,269
  • 1
  • 16
  • 29

3 Answers3

15

The easiest way to do this is to use the promise.finally shim.

  • Add it with npm install --save promise.prototype.finally
  • Add the typings: npm install --save-dev @types/promise.prototype.finally
  • In your main class, before bootstrapping the application, add the following code:
import { shim } from 'promise.prototype.finally';
shim();

You should now be able to use finally on your promises.

Tom Spencer
  • 7,816
  • 4
  • 54
  • 50
  • I am getting an error with typescript 2.1.5 saying all declaration of promise must have identical declaration. – Shyamal Parikh Jan 22 '17 at 12:33
  • @ShyamalParikh thankfully the DefinitelyTyped repo has been updated with the correct typings. I've updated my answer above to reflect this. – Tom Spencer Jan 24 '17 at 11:22
  • 2
    @fiznool, Thanks for that. One thing to add, (I'm using Angular4) I think it's best to place the shim in the polyfills.ts file. I placed the following at the bottom of that file `/*************************************************************************************************** * PROMISES .finally SHIM */` `import { shim as finallyShim } from 'promise.prototype.finally'; finallyShim();` – PigBoT Jul 06 '17 at 15:37
1

This is usually done using Promise.always. This takes one function, and adds a new .then on the promise that gives the same function for both success and fail states. If the function is not available in the given promise-based environment, it's pretty easy to polyfill in.

Promise.always = function(p, fn) {
  return p.then(fn, fn);
}

usage:

var prom = fetch('/api/users').then...
Promise.always(prom, () => {
  this.userLoaded = true;
});
return prom;
Katana314
  • 8,429
  • 2
  • 28
  • 36
  • You should **not** modify the `Promise` object. https://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/ – James Monger Nov 16 '16 at 22:10
1

Modern solution in 2019-2020

First of all, you should avoid manually adding polyfills without a good reason for it, don't do it blindly because you've read it somewhere.

The problem you encounter has two sides: typing declarations and the implementation.

In order to use Promise.finally in your code without typing errors you should add es2018.promise to the lib option in your tsconfig.json file.

For modern projects you should use the following configuration (which is default in Angular 8):

{
  "compilerOptions": {
    …
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

This will fix the typing errors you have in the editor.

Also, according to the docs and my observations the correct polyfill for Promise.finally will be added by the Angular compiler automatically, you don't have to install or add anything.

But, in general, you could add a polyfill (only if it is proven to be required) in ./src/polyfills.ts file using core-js library. Always try to use core-js instead of other libraries, cause it's an industry standard and it's used by Angular internally.

For example, Promise.finally polyfill could be added like this:

import 'core-js/features/promise/finally';


See more at core-js documentation.

Also, make sure to read browser-support and differential-loading articles of Angular documentation.

Slava Fomin II
  • 26,865
  • 29
  • 124
  • 202