160

Bluebird offers a finally method that is being called whatever happens in your promise chain. I find it very handy for cleaning purposes (like unlocking a resource, hiding a loader, ...)

Is there an equivalent in ES6 native promises?

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Aric Lasry
  • 1,769
  • 3
  • 11
  • 11

1 Answers1

280

As of February 7, 2018

Chrome 63+, Firefox 58+, and Opera 50+ support Promise.finally.

In Node.js 8.1.4+ (V8 5.8+), the feature is available behind the flag --harmony-promise-finally.

The Promise.prototype.finally ECMAScript Proposal is currently in stage 3 of the TC39 process.

In the meantime to have promise.finally functionality in all browsers; you can add an additional then() after the catch() to always invoke that callback.

Example:

myES6Promise.then(() => console.log('Resolved'))
            .catch(() => console.log('Failed'))
            .then(() => console.log('Always run this'));

JSFiddle Demo: https://jsfiddle.net/9frfjcsg/

Or you can extend the prototype to include a finally() method (not recommended):

Promise.prototype.finally = function(cb) {
    const res = () => this;
    const fin = () => Promise.resolve(cb()).then(res);
    return this.then(fin, fin);
};

JSFiddle Demo: https://jsfiddle.net/c67a6ss0/1/

There's also the Promise.prototype.finally shim library.

Miguel Mota
  • 20,135
  • 5
  • 45
  • 64
  • 19
    It's worth mentioning this .catch() will catch not only original Promise's failure, but also all errors thrown in original .then() handler. So it's easy to accidentally suppress some error message with this code. – Frax Jun 14 '17 at 22:32
  • 1
    if (Promise.prototype.finally == undefined) { Promise.prototype.finally = function (callback) { return this.then(function (result) { return Promise.resolve(callback()).then(function () { return result; }); }, function (error) { return Promise.resolve(callback()).then(function () { throw error; }); }); }; } – 4esn0k Aug 09 '17 at 18:57
  • 1
    Why is the `prototype.finally` approach not recommended? – Jan Hommes Oct 18 '17 at 13:45
  • It took me a while to figure out how `finally` should receive a parameter as state no matter the promise resolve/reject `Promise.prototype.finally = function(cb) { const res = () => this const fin = (value) => Promise.resolve(cb(value)).then(res) return this.then(fin, fin)` – Ace Oct 22 '17 at 17:25
  • @JanHommes it is never recommended to extend prototypes with custom methods. When the spec decides to add a native implementation of `.finally()` or whatever method you're adding to the prototype, you'd end up with a broken implementation and your app may stop working on newer browsers. – Jerome Indefenzo Dec 07 '17 at 16:06
  • @JeromeIndefenzo Extending prototypes behind a feature check is fine. This is commonly done to polyfill newer features wherever they're not present. – Roy Tinker Feb 23 '18 at 20:35