Excellent blog translation series

Translation from Jake Archibald Blog

Which return of the following js functions executes?

function test() {
  return 'one';
  return 'two';
  return 'three';
}
Copy the code

You might say, “I’ll do the first one.”

But I will try to convince you that it will be the “last” return that gets executed.

Don’t worry, the above function must return one, but in this case, the first return declaration organizes the execution of the other return statements. That is, the last Return statement here is Return ‘one’, and it is the winner. Of course, it is the first Return declaration, but I’m still right.

I know you’re thinking, “Shut up.” But let me take my time.

finally

A finally statement is something like this:

function finallyTest() {
  try {
    console.log('one');
    return 'three';
  } catch (err) {
    console.log('error');
  } finally {
    console.log('two');
  }
}

console.log(finallyTest());
console.log('four');
Copy the code

The above function prints ‘one’, ‘two’, ‘three’, ‘four’ in order. A finally block is always executed after a try/catch execution, even if a try/catch is returned by a return.

I didn’t use finally very often in JavaScript until recently, when I found that I needed to use it in an async function like this:

async function someAsyncThing() { startSpinner(); try { await asyncWork(); } catch (err) { if (err.name === 'AbortError') return; showErrorUI(); } finally { stopSpinner(); }}Copy the code

However, the exciting thing is that finally gives us the opportunity to execute multiple returns ina single function call:

function manyHappyReturns() { try { return 'one'; } finally { try { return 'two'; } finally { return 'three'; }}}Copy the code

Also, executing manyHappyReturns() results in ‘three’

The last Return always wins.

It’s not the last return in the function that wins, that would be crazy. It is the last return statement to be executed.

The last Return wins, just as the last variable assignment wins. In fact, this phenomenon is a lot like variable assignment: a return assigns a value to the result of a function, so the following return overwrites the previous return. This is also true in Java and Python. Thanks to Daniel Ehrenberg for helping me understand this tip.

As a side effect, a return from finally clears the Error thrown:

function catchThis() { try { throw Error('boom'); } finally { return 'phew'; }}Copy the code

CatchThis () results in: ‘phew’.

Bonus: Promises

The async function behaves the same as the normal function above in this respect (except that the return value is wrapped as a promise). However, promise.finally() behaves differently.

const promise = Promise.resolve('one').finally(() => 'two');
Copy the code

Here, the promise is implemented as ‘one’. This may be because the response to a promise is a callback function, and the caller of the callback function (in this case, the promise itself) has no way of telling whether a function executes undefined or no return statement at all. Therefore, it does not emulate the ordinary finally feature above, but simply chooses to ignore it.

Although, promise.finally does influence when promises are fulfilled:

const wait = (ms) => new Promise((r) => setTimeout(() => r(), ms));

const promise = Promise.resolve('one').finally(async () => {
  await wait(2000);
  return 'two';
});
Copy the code

Here, the promise is still implemented as ‘one’, but after 2s.