1

In JS functions, the last return wins

 3 years ago
source link: https://jakearchibald.com/2021/last-return-wins/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

In JS functions, the last return wins

Posted 24 June 2021 and I apologise in advance

In JavaScript functions, which return wins?

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

You might say, "well it's the first one", but I'm going to try and convince you it's the last one.

Don't worry, the function above definitely returns 'one', but in this case the first return statement prevents the others from executing. The last return is return 'one', and that's the one that wins. Sure, it's also the first return, but I'm still right. [folds arms and looks smug]

I know what you're thinking, you're thinking "shut up jake", but bear with me…

Finally

finally is a thing:

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

console.log(finallyTest());
console.log('four');

The above logs 'one', 'two', 'three', 'four'. The finally block always runs after a try/catch, even if the try or catch return.

I hadn't used finally much in JavaScript, but I find myself using it quite a bit in async functions, in patterns like this:

async function someAsyncThing() {
  startSpinner();

  try {
    await asyncWork();
  } catch (err) {
    if (err.name === 'AbortError') return;
    showErrorUI();
  } finally {
    stopSpinner();
  }
}

Anyway, the exciting thing about finally is it gives us the opportunity to return many times from a single function call:

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

…and the result of calling manyHappyReturns() is 'three'. The last return always wins. The same happens in Java and Python too. Thanks to Daniel Ehrenberg for making me aware of this little quirk!

What's the practical application of this?

There isn't one. Thanks for reading! Please never quiz folks about this in a job interview.

Bonus: Promises

Async functions behave the same as above, except they return a promise. However, promise objects behave differently:

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

Here, promise fulfils with 'one'. This is probably because promise reactions are callbacks, and the caller of a callback (which is the promise in this case) has no way of telling the difference between a function that runs return undefined and one that doesn't run return at all. Since it can't mimic the finally edge case above, it just ignores it.

Although, promise.finally does impact when the promise resolves:

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

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

In this case promise still fulfils with 'one', but it takes two seconds to do so.

View this page on GitHub


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK