Reputation: 6336
I'm searching for some eslint option, or some other way to detect missing the 'await' keyword before calling async methods inside a class. Consider the following code:
const externalService = require('./external.service');
class TestClass {
constructor() { }
async method1() {
if (!await externalService.someMethod()) {
await this.method2();
}
}
async method2() {
await externalService.someOtherMethod();
}
module.exports = TestClass;
There will be no warning if I will convert method1 to:
async method1() {
if (!await externalService.someMethod()) {
this.method2();
}
}
I tried to do on the '.eslintrc' file:
"require-await": 1,
"no-return-await": 1,
But with no luck. Anyone have an idea if it is even possible? Thanks a lot!
Upvotes: 12
Views: 7767
Reputation: 15995
typescript-eslint has a rule for this: no-floating-promises
This rule forbids usage of Promise-like values in statements without handling their errors appropriately ... Valid ways of handling a Promise-valued statement include
await
ing, returning, and either calling.then()
with two arguments or.catch()
with one argument.
As you probably figured out from the name, typescript-eslint is designed to add TypeScript support to eslint, but you can use it with JavaScript as well. I guess it's your call to decide whether it's overkill for this one rule, but here are the steps:
Generate a tsconfig.json
file
npx tsc --init
Install dependencies
npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
Modify your .eslintrc
file
Based on my testing it looks like you'll need these entries at a minimum:
{
"parser": "@typescript-eslint/parser",
"parserOptions": { "project": "./tsconfig.json" },
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-floating-promises": ["error"]
}
}
If there are places where you want to call an async function without using await
, you can either:
Use the void
operator as mentioned in the documentation for the rule, e.g.
void someAsyncFunction();
Or just change error
to warn
in the .eslintrc
configuration above
The documentation for setting up typescript-eslint is here for more info: https://typescript-eslint.io/docs/linting/linting
Next time you run eslint you should see the rule applied:
$ npm run lint
...
./services/jobService.js
11:5 warning Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises
Since you mentioned VS Code specifically, this also integrates great with the ESLint plugin:
Upvotes: 15
Reputation: 769
Consider using the combination of eslint rules for a better version of checking await
:
return-await with try-catch option to able catch the Promise rejection (reference)
Upvotes: 1
Reputation: 788
There is an ESLint plugin for this that you can use as an alternative to the typescript-eslint route:
https://github.com/SebastienGllmt/eslint-plugin-no-floating-promise
Upvotes: 1
Reputation: 943591
require-await
says "Don't make a function async
unless you use await
inside it".
This is because async
has two effects:
await
inside itThe former is rarely useful which mean if you aren't using await
inside the function you need to question why you marked it as async
.
no-return-await
stops you from doing:
return await something
Because await
unwraps a value from a promise, but returning a value from an async
function wraps it in a promise.
Since just returning a promise causes that promise to be adopted, combining return
with await
is just bloat.
So neither of those do what you want.
Which brings us to your actual desire.
Such a feature does not (as far as I know) exist in ESLint, and I don't think it would be useful to have one.
There are lots of use cases where you don't want to await something returned by an async
function.
e.g.
const array_of_promises = array_of_values.map( value => do_something_async(value) );
const array_of_resolved_values = await Promise.all(array_of_promises);
The above is a common use-case where you want to run a bunch of async functions in parallel and then wait for them all to resolve.
Another example is the case that no-return-await
is designed to detect!
Cases like these are common enough that most people wouldn't want their toolchain calling them out for doing it.
Upvotes: 3