Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add information to no-return-await docs about potential pitfalls. #9695

Closed
Alxandr opened this issue Dec 8, 2017 · 7 comments
Closed

Add information to no-return-await docs about potential pitfalls. #9695

Alxandr opened this issue Dec 8, 2017 · 7 comments
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion documentation Relates to ESLint's documentation help wanted The team would welcome a contribution from the community for this issue rule Relates to ESLint's core rules

Comments

@Alxandr
Copy link

Alxandr commented Dec 8, 2017

return await has subtly different semantics from just return in async functions. Example:

async function failing() {
  throw new Error('foo');
}

async function noAwait() {
  try {
    return failing();
  } catch (e) {
    return 'oops';
  }
}


async function withAwait() {
  try {
    return await failing();
  } catch (e) {
    return 'oops';
  }
}

noAwait().then(console.log, console.warn);
withAwait().then(console.log, console.warn);

This will call console.warn with the 'foo' error, which is thrown from noAwait. But it will log oops from the withAwait function. This is confusing behaviour, which might completely catch people off guard. So no, the await after return is not always superfluous, and recommending it's removal might lead to subtle changes that was not expected.

@eslint-deprecated eslint-deprecated bot added the triage An ESLint team member will look at this issue soon label Dec 8, 2017
@platinumazure
Copy link
Member

Hi @Alxandr, thanks for the issue!

We always appreciate improvements to our documentation, so definitely feel free to submit a PR. That said, do you know why the behavior you described is the way it is? It would be great to have both an example and an explanation that draws from the spec, since some users will understand the example better and others will understand the explanation/spec better.

@platinumazure platinumazure added accepted There is consensus among the team that this change meets the criteria for inclusion documentation Relates to ESLint's documentation rule Relates to ESLint's core rules and removed triage An ESLint team member will look at this issue soon labels Dec 8, 2017
@not-an-aardvark
Copy link
Member

In fact, the no-return-await rule does not report these cases. That said, I agree that it would be useful to document them and describe why the rule does not report them.

@Alxandr
Copy link
Author

Alxandr commented Dec 8, 2017

Well, what do you know? I'm sorry for coming here with misinformation :(. But regardless, the difference is explained pretty well here: https://jakearchibald.com/2017/await-vs-return-vs-return-await/

Basically, the issue is that when you do return <a promise>, it leaves the function with a promise, and then it's resolved. You can think of it like every async functions being implicitly wrapped in Promise.resolve I guess. This means that you exit the try block before the promise is resolved (or rejected).

I don't know where in the spec this is described, as I don't normally read the javascript spec, but I would guess it's for the same reason that in promise.then you can return both normal values and new promises. Essentially it implements both .map and .flatMap (or map and bind if you're into Haskell and friends).

This behavior makes me wish I could have a linter tell me to always require await before return on an async value instead of never because if you leave it out and then refactor into a try-catch, it can bite you in the ass. But that would require a type-system, so I get that that's not really doable in eslint. But the fact that there is a linter rule that encourages you to remove await before return makes me worried that there will be developers who do not understand these semantics, and will take the linter rules as "good advice". Then they will be left with subtle bugs in their code, and not understand why it's not invoking their catch handler (which is a pretty absurd issue to try to debug).

@hazolsky
Copy link

hazolsky commented Dec 11, 2017

Good catch, i had same problem recently 👍

@aladdin-add aladdin-add added the help wanted The team would welcome a contribution from the community for this issue label Jun 1, 2018
@marla294
Copy link
Contributor

If this still needs help, I am interested in taking this one on. I'll probably need a week or so (July 31st).

It seems like the page that needs updating is this one. As you guys already mentioned, the following case is already on the page under "The following patterns are not warnings:"

async function foo() {
try {
return await bar();
} catch (error) {}
}

So no need to update that part. But, I can see where Alxandr is coming from, it seems like the top paragraph is a little misleading, saying in the first line:

Inside an async function, return await is useless.

It is a little bit confusing that the rule says return await is useless and then further on down the page, says it allows it under some circumstances. I'd like to go in and clean up that first paragraph a little bit to make it clearer what is meant.

LMK if any issues with my taking this on. Otherwise, I'll get to it.

@platinumazure
Copy link
Member

@not-an-aardvark Any direction you want to provide in response to this comment? Or does the proposal there sound good? Thanks!

@not-an-aardvark
Copy link
Member

Sounds good to me!

@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Jan 31, 2019
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Jan 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion documentation Relates to ESLint's documentation help wanted The team would welcome a contribution from the community for this issue rule Relates to ESLint's core rules
Projects
None yet
Development

No branches or pull requests

6 participants