4

How can I lint my Javascript code to identify promise chains (promise.then().then().then()...) that do not have a fail block at the end? Do any of the existing tools (JSHint, JSLint, the Flow static type checker, Typescript, ...?) allow this?

The motivation for this, candidly, is that sometimes I just forget to put one in code that I write. Then, if an error occurs in that code, it will fail silently and it can be a beast to debug. Instead, it would be better software engineering to be able to catch those errors at lint-time in the same way that I can use linting to identify typos in variable names

For example:

q(this_function_returns_a_promise())
.then(function(data) {
  console.log('The promise returned some data: ' + JSON.stringify(data));
})
// .. more thens, spreads, alls
.then(function(modified_data) {
  this_function_will_throw_an_error(modified_data);
})
// .. more thens, spreads, alls
.then(function(modified_modified_data) {
  console.log('I will not be printed, logging and execution will just stop in ' +
    'the middle then()');
});
// if only there was a .fail(function(err) { ... }) here that printed the error!
cfogelberg
  • 1,468
  • 19
  • 26
  • 1
    It's not something I've considered before so I can't give a direct answer, but if there isn't an obvious option available, then your best bet would probably be eshint, as that allows for custom rules to be added relatively easily, unlike most of the other options you mentioned. – Simba Jun 26 '15 at 08:16
  • @Simba: Did you mean [ESLint](https://github.com/eslint/eslint)? (I can't find an "eshint") (Looks really cool, btw) – T.J. Crowder Jun 26 '15 at 08:20
  • @T.J.Crowder - uh, yes, that is what I meant. (typing too quickly for my own good; sorry!) – Simba Jun 26 '15 at 08:23
  • How do you expect to distinguish `return promise.then().then();` which is ok without `fail` section? – Kirill Slatin Jun 26 '15 at 09:09

1 Answers1

0

This is not something you can lint for or otherwise identify via static analysis. There are many (most?) cases where a promise chain does not provide a catch and doesn't need to or want to, because the catch will happen somewhere downstream.

What you need to do is use your promise library's facilities for reporting on "zombie" promises, or uncaught rejected promises. This will happen at run-time, not "compile" time. The specifics of how to do that will differ from library to library. Some browsers are already beginning to implement things along this line. In Chrome, try typing the following into the console:

> Promise.resolve().then(function() {throw "throw";})
< Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
< Uncaught (in promise) throw
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  • 1
    Marking this as correct as it appears to be the best option. Leaving aside the practicaility of linting for promise chains without failure catches in a language like Javascript, it is still a valuable thing to be able do because it helps avoid errors. In situations where a promise chain does not need one (e.g. a method returning a promise for consumption) then linter annotations which mark that promise chain as un-failured would fill the same purpose. – cfogelberg Jul 03 '15 at 11:44