Finally in Promises & Try/Catch
Tags: javascript, learning, programming
Published: 2018-09-19 00:43:06

---
title: Finally in Promises & Try/Catch
published: true
description: 
tags: javascript, learning, programming
cover_image: https://thepracticaldev.s3.amazonaws.com/i/szwmwyn7i3zjxosp2vs3.png
---

Lately, I've been experimenting more with the `async`/`await` keywords in JavaScript. I noticed that I sometimes struggle to reconcile the strategies I use with Promises with the way I need to write code in the newer syntax. Most recently, I was playing around with `finally` in some `try`/`catch` blocks and came upon some behavior I didn't expect.

This post assumes a general understanding of how asynchronous JavaScript code works - particularly, how Promises work. (If you're looking for an in-depth explanation of async JS from callbacks to the async/await keywords, there's a pretty good overview on [javascript.info](https://javascript.info/async) - you can also check out [Mostafa Gaafar's article](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) for some of the neat features of async/await.)

For context - in the JavaScript codebase I spend a lot of my time in, we've historically dealt with asynchronous actions by using Promises heavily. Generally, this pattern is a lot more familiar to me:

```javascript
const loadSomething = () => {
  return fetchSomeData()
    .then(data => doSomethingWith(data))
    .catch(error => logAndReport(error))
}
```

And this is less familiar:

```javascript
const loadSomething = async () => {
  try {
    const data = await fetchSomeData()
    return doSomethingWith(data)
  } catch (error) {
    logAndReport(error)
  }
}
```

# `finally`...?

You'll notice that a `finally` callback/block is missing from both of the examples above. I don't use either often in my code, which led me to a misunderstanding (of both, really). Let's dive into the differences between this concept in Promises and in try/catch!

## `finally` in Promises

When you use the `somePromise.then(x).catch(y).finally(z)` pattern, your business logic is generally happening in the `then` callback (`x`, above - what you want to do once `somePromise` has resolved) or in the `catch` callback (`y` above - returns what you want to pass along in case something goes horribly wrong). You might never have even used `finally` in your code - and that's fine. 

According to the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally#Description), a `finally` callback allows you to execute logic once your Promise has been settled - resolved or rejected - one way or the other. It has absolutely no impact on the _value_ that your promise will resolve to - it doesn't even have access to it. In fact, the documentation states that:

> `Promise.resolve(2).finally(() => {})` will be resolved with `2`.

This means (somewhat counterintuitively) you can sprinkle `finally` callbacks liberally throughout your promise chain without changing the final result that it will resolve to:

```javascript
// Please don't do this 😅

Promise.resolve({ some: 'data' })
  .finally(() => { console.log('WHALE HELLO THERE 🐋') })
  .then(data => ({ ...data, anAdditional: 'key'  }))
  .finally(() => { console.log('Looks like we made it past the first step 🙏') })
  .then(data => ({ ...data, yetAnother: 'thing added' }))
  .finally(() => { console.log("We're done I think 🙌") })
  .then(data => {
    console.log('Final result:', data)
  })
```

If you run this code, you should see this:

![result of executing the above code: Each step is logged to the console sequentially; the final result is an object containing three keys](https://thepracticaldev.s3.amazonaws.com/i/7o2uc2fv1nv5wll9hbrl.png)

## `finally` in try/catch blocks

The try/catch/finally pattern has been around for a _long_ time in JavaScript - since version 1.4 (ES3 specification, around 1999). There are a couple of logical parallels I'd drawn between this pattern and how promises are handled:

**`try`/`then`:**
This is where our "happy path" logic goes - if nothing breaks, all the action happens here!

**`catch`:**
This is where we end up when things go wrong, and gives us a chance to redeem ourselves 🙏

**`finally`:**
This logic will execute after the `try`/`then` (and possibly `catch`) logic has completed. This code runs no matter what, whether we've encountered an error or not.

The difference here that tripped me up is related to `return` statements. If your `finally` block _does not_ include a return statement, it has _no effect_ on the return value. However, if you return a value from a `finally` block, that value will override all other returns and be the final result of your function. (Check out [this example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#Returning_from_a_finally_block) from the docs!) 

```javascript
// This worked as I expected.
const returnFromTryCatch = (someFunction) => {
  try {
    return someFunction()
  } catch (error) {
    return `Caught an error: ${error}`
  } finally {
    // This block has no effect on the return value.
    console.log('All done!')
  }
}

// This was a surprise to me!
const returnFromFinally = (someFunction) => {
  try {
    return someFunction()
  } catch (error) {
    return `Caught an error: ${error}`
  } finally {
    // Wait... so I'm just swallowing my return and error handling?
    return 'All done!'
  }
}
```

This makes sense, but it felt inconsistent to me. My experience with Promises reared its head - why should a `finally` block _ever_ be allowed to override the value a function returns?

![pixel art of a woman looking at her laptop in deep thought](https://thepracticaldev.s3.amazonaws.com/i/h26k6giyyy38p4v6y8w9.png)

# Finding the Reason

[_Finally,_](https://en.wikipedia.org/wiki/Semantic_satiation) I pinged my tech lead detailing my annoyance, and he sent me [a link to a related StackOverflow discussion](https://stackoverflow.com/questions/3837994/why-does-a-return-in-finally-override-try). Seeing the ECMAScript specification (emphasis mine) for this behavior helped it settle into place in my brain:

> The production `TryStatement : try Block Finally` is evaluated as follows:
> 
> Let B be the result of evaluating Block.
> Let F be the result of evaluating Finally.
> **If F.type is normal, return B.**
> Return F.

(It's worth noting the "completion types" according to the [ECMAScript spec](https://tc39.github.io/ecma262/#sec-completion-record-specification-type) are "One of normal, break, continue, return, or throw" - I have assumed that a function that does not include a `break`, `continue`, `return`, or `throw` keyword qualifies as "normal." Kind of weird semantics there.)

### Note on Multiple Return Statements

The code samples in this post do not utilize a single return. I'm not going to get too far into the debate around multiple return statements - I will say that in general, having a single return for longer functions has served me well in the past, but I've found them less helpful in shorter blocks. It probably would have made my life easier in this case, though!