Can ESLint help you prevent Unhandled-Promise-Rejections?
N

3

12

Does eslint have any ability to warn about places to prevent Unhandled-Promise-Rejections?

Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. - DEP0018

You know what, I kind of like how the engine currently handles Unhandled-Promise-Rejections; because when you have an Unhandled-Promise-Rejection, instead of your whole service crashing, the service keeps running and only the part that was dependent upon the erroneous promise instance fails to complete. Let's say the error was caused by some user input not anticipated by the programmer during validation. The very async function that had an exception lives on to serve other calls (ones that do not have that same unanticipated user input). Yes, there is trash in the program at this point, in the form of forever awaiting awaits that never resolve, but to me that's more robust than allowing the service to crash completely.

Anyway, I guess someone else has already decided that perfection is more important than robustness.

Therefore, it is time for me to make my code ugly and perfect by having .catch(()=>{}); appended shortly after all those awaits in my code that looked clean as MOP&GLOW previously.

Does ESlint offer anything to assist me in locating promises without catches? Are there any spec additions that are in the works, for addressing this ugliness and inconvenience?

Personally, I wish I could configure the engine to just terminate code that is down the promise chain from an UnhandledPromiseRejection. I certainly would like to address the issue more easily than adding all those .catch(()=>{}) to all my async function calls that are awaited.

Nicobarese answered 24/7, 2020 at 8:0 Comment(5)
This should help you npmjs.com/package/eslint-plugin-promise, look at catch-or-return, which IMHO will increase the MOPnGLOW even furtherDecapitate
@Decapitate what does MOPnGLOW mean?Avalanche
@Avalanche It's actually called mop&glow. It is a product for making a floor shine.Nicobarese
ah...yes... that makes... sense still udderly confused but right onAvalanche
@Avalanche It was a bad analogy on my part; I failed at being colorful.Nicobarese
D
7

ESLint itself does not have the functionality you are looking for, but there is a highly popular plugin called eslint-plugin-promise.

Specifically, the catch-or-return rule does what you are asking for:

Ensure that each time a then() is applied to a promise, a catch() is applied as well. Exceptions are made if you are returning that promise.

Valid

myPromise.then(doSomething).catch(errors)
myPromise
  .then(doSomething)
  .then(doSomethingElse)
  .catch(errors)
function doSomethingElse() {
  return myPromise.then(doSomething)
}

Invalid

myPromise.then(doSomething)
myPromise.then(doSomething, catchErrors) // catch() may be a little better
function doSomethingElse() {
  return myPromise.then(doSomething)
}
Decapitate answered 25/7, 2020 at 13:56 Comment(0)
B
21

I wonder why no one mentioned the "No floating promises" rule from "typescript-eslint", which forces all promises to be handled appropriately either with async/await or then/catchhttps://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-floating-promises.md Probably it should be called "No unhandled promises". :)

Biggin answered 9/10, 2020 at 16:20 Comment(3)
This should be marked as the most recent, best answer. As of today, eslint-plugin-promise hasn't had a release in two years, whereas typescript-eslint is the standard plugin for typescript ESLint and its latest release was two days agoNitramine
@ppicom Judging something solely on the package's release doesn't always carry much merit. Highly focused packages typically don't need to be updated if there are not bugs to fix and no new features are applicable. Also, your comparison is against a plugin focused on the promise feature of the language against a plugin supporting the whole language.Cavernous
@DannyHurlburt I don't quite understand the point you are trying to make. Why install another plugin when the linter already supports that feature? Moreover, the latest release is sometimes an indicator of how active are the maintainers and can give a rough idea of whether a package is maintained or not. Having said that, there was a release for eslint-plugin-promise so my previous comment is 50% invalidated :)Nitramine
D
7

ESLint itself does not have the functionality you are looking for, but there is a highly popular plugin called eslint-plugin-promise.

Specifically, the catch-or-return rule does what you are asking for:

Ensure that each time a then() is applied to a promise, a catch() is applied as well. Exceptions are made if you are returning that promise.

Valid

myPromise.then(doSomething).catch(errors)
myPromise
  .then(doSomething)
  .then(doSomethingElse)
  .catch(errors)
function doSomethingElse() {
  return myPromise.then(doSomething)
}

Invalid

myPromise.then(doSomething)
myPromise.then(doSomething, catchErrors) // catch() may be a little better
function doSomethingElse() {
  return myPromise.then(doSomething)
}
Decapitate answered 25/7, 2020 at 13:56 Comment(0)
C
2

Porting your code to use async/await instead of promise chains will help to begin with, and makes your code prettier again; there is a codemod that can help you with that.

Anyway, I guess someone else has already decided that perfection is more important than robustness.

The new behavior is more sound, if you ask me (especially when using async/await, where .catch(() => ...) is just the usual catch (e) { ... }, and not catching exceptions, well...)

If you do use .then() syntax, then adding .catch(() => {}) signals to the reader that you explicitly do not care about any errors that occur.

Chung answered 24/7, 2020 at 8:33 Comment(8)
I'm already using async/await heavily. However, each async function call returns a promise and 'try/catch' syntax isn't much better than .catch()=>{}; It seems like the absence of '.catch()=>{}' would be a clear enough indication that I don't care, without having to be so verbosely explicit. In the end, the goal is to prevent the server from crashing over something I consider minor.Nicobarese
Well, you can write a helper const swallowErrors = (p) => p.catch(e => console.warn(e)), and wrap the promises you don't care about in that, for example.Chung
Yep, that's a little nicer. I've been playing around with that too. I'm just trying to discover an elegant best practice for dealing with this and was hoping eslint might point to all the place that need implementation of that practice.Nicobarese
For what it's worth, the PyCharm/WebStorm IDE has an annotation for ignored promise return values; not sure if ESLint does.Chung
That's a need tool you linked. I'm curious to see if they handle promise.then conversions to async/await in a manner that prevents unhandled-promise-rejections. Because each promise awaited is potential a unhandled-promise-rejections (if it has no catch).Nicobarese
Each regular function called is also potentially an uncaught exception. :)Chung
True, that's good point for me to think about. Maybe it does make sense that they should crash your service just like exceptions in regular functions do, but its just hard for me favor a crashed service over one that runs robustly by simply auto ignoring these unhandeled promise rejects. Again, a good point for me to think about...Nicobarese
It can't be robust, if it ignores all unhandled promises. You should always handle exceptions explicitly. Even if that means having a try-catch in the entry point method and just log/ignore the exception.Provost

© 2022 - 2024 — McMap. All rights reserved.