DEV Community

Michael De Abreu
Michael De Abreu

Posted on

Finally, we have a finally. But we already had one.

Promise
I like to dig around the new features that are coming to JS, even when most of the time we need to transpile them down, you should know that you can, and should, deploy to production using ES2015+ syntax today. In the current list of proposals in stage-3, was something that catch my attention. That was the Promise.prototype.finally.

FINALLY!

So we now have a finally method into Promise. A finally method will be called always, and doesn't care if the Promise was fulfilled or rejected. It will no alter the value of the resolve promise, but could reject the promise with a new reason. Currently there are several implementations in other future libraries in NPM, as in the current proposal is written. However this, soon to be standard, will allow to use the method in evergreen browsers.

When to use it

The finally statement is really common in programming, specially when dealing with external connections that must be closed even in an unsuccessful operation, such as reading external files or database operations. Such connections need to be closed, and doesn't matter if the operation was successful or not, we just need to close the connection.

How to use it

The finally method is really straightforward, every promise will have one, and it will return a promise as well, so you could chain as usual.

Promise
    .resolve(3)
    .finally(
        () => {
            console.log('FINALLY!');
            return 4;
        }
    )
    .then(
        value => console.log(value) // Output: 3
    );
Enter fullscreen mode Exit fullscreen mode

As you may notice, resolving a value in the finally, have not effects. However, you should know that, per specification, a Promise can be rejected from a finally method.

Promise
    .resolve(3)
    .finally(
        () => {
            console.log('FINALLY!');
            throw 4;
        }
    )
    .then(
        value => console.log(value) // Does not print
    ).catch(
        error => console.log(error) // Output: 4
    );
Enter fullscreen mode Exit fullscreen mode

How to use it, today

Well, you could use one of the different future libraries, such Bluebird, or the finally shim and use it with ES2017, that have a new syntax to deal with promises, async/await. I really love them, and they are very handy to work with promises, writing code that looks very clean. This couple makes every function, an asynchronous function, that are resolved as a regular Promise. So, you could just do finally after the declaration of the async function.

const promiseA = async () => {
    return await 3;
}
promiseA.finally(() => console.log('The promise either was a success or a failure'));
Enter fullscreen mode Exit fullscreen mode

The finally method will be called, as per the specification. But, what if we need to try/catch inside the async function (That you should). Then, we could use the finally statement.

const aSuperUsefulPromise = async () => {
  try {
    return await PromiseThatCouldThrow();
  } catch (error) {
    console.log(error);
    // We don't modify the promise here, just catch the error and handle it.
  } finally {
    return await 4;
  }
}

console.log(await aSuperUsefulPromise()) // Outputs: 4
Enter fullscreen mode Exit fullscreen mode

Wait... What?
Well, when dealing with try/catch/finally you CAN modify the value of a resolved promise. And this is really important to notice and understand, as you may expect a different result. So, you should never return inside a finally statement. It maybe weird to you, cause JS have a implicit return statement, but that return will be called after the finally statement, not before.

Conclusion

The finally method in Promises will be something, but we could accomplish more or less the same behavior using current try/catch/finally statements, we need to be careful though.

I learn a lot writing this article, and I hope that you could understand a little more about the new finally method. Thanks you for reading, and as usual, if I made a mistake, please, guide me in the comments below, I will deeply appreciate it.

Top comments (2)

Collapse
 
fristys profile image
Momchil Georgiev

Or you could use Bluebird and have finally and a crapton of other cool features + a more performant promise implementation than the native one.

Collapse
 
michaeljota profile image
Michael De Abreu

I do mention the use of Bluebird, but I wasn't aware about the performance of that implementation. Thanks you. :)