0

I had a typo on the .then block of a promise and the promise kept failing. I suppose I didn't realize if there was a type it would go to .catch. It took quite a bit of digging to figure out that was the mistake (kept assuming it was something wrong with the promise/async/etc call.)

Is there a way to get JS to tell me "hey, there's a mistake in your .then block!"

code

     searchAPI(name)
      .then(data => {
        // typo was LowerCase instead of toLowerCase
        let filtereddowndata = data
          .filter(item =>
            item.title.toLowerCase().includes(name.LowerCase())
          )
               etc etc

      })
      .catch(function() {
        console.log("no match found"); // kept going here.
      });
Kyle Pennell
  • 5,747
  • 4
  • 52
  • 75
  • 1
    Log the error in the catch callback? – jonrsharpe Sep 07 '19 at 15:38
  • 1
    Regarding your question, I seem to remember that it's near impossible to automatically handle all errors thrown by callbacks passed to `then`, not without having passing a callback through the `catch` function. Meaning, in other words, exceptions thrown by callbacks passed to `then` function do not cause events of type [`error`](https://html.spec.whatwg.org/multipage/indices.html#event-error) to be dispatched. Of course, the latter is specified by HTML 5, not ECMAScript, and I cannot at the moment find either confirmation or denial of ECMAScript handling this in any way. – Armen Michaeli Sep 07 '19 at 16:22
  • 1
    @amn Have a look at [Why are exceptions used for rejecting promises in JS?](https://stackoverflow.com/q/21616432/1048572) – Bergi Sep 07 '19 at 16:30

2 Answers2

2

The actual error sent to the .catch() (which you were ignoring in your code) would have given you a good clue why the .catch() was being triggered. Use something like this:

.catch(function(e) { 
    console.log(e);
    // any other processing code here
 });

I always make sure to log the actual error in my .catch() statements so I can always see exactly why it got triggered and don't blindly assume anything about how the code got here.

This is also why node.js makes it a console warning (and eventually a run-time error) when you don't have any .catch() because the try/catch built into .then() will hide errors from you if you don't expose them yourself in a .catch().


The above would have been enough to give you the precise error in this case. But there are other situations where (for debugging purposes) you sometimes benefit from inserting your own try/catch statements around more localized areas of your code. That would have also shown you what was happening in your .then() handler.

You can run this snippet to see the actual error.

     // simulate your searchAPI() call
     function searchAPI() {
        return new Promise(resolve => {
            resolve([{title: "Superman"}, {title: "Spiderman"}]);
        });
    }
    
    let name = "Joe";
    
    searchAPI(name).then(data => {
        // typo was LowerCase instead of toLowerCase
        let filtereddowndata = data.filter(item =>
                item.title.toLowerCase().includes(name.LowerCase())
        );
    }).catch(function(e) {
        // console.log(e) will work with normal Javascript
        // here in a stackoverflow snippet where console.log has been replaced
        // you have to look at console.log(e.message) to see the error
        console.log("searchAPI failed - ", e.message);
    });
jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

I can only emphasise @jfriend's answer that you should always reject with proper error messages and log them.

However, it is also important to understand how promises get rejected and which .catch() callbacks will handle rejections from where. It's possible to better differentiate error origins by not using the traditional .then(…).catch(…) pattern, and even tag each error with the function it's coming from.

In your case, the error message "no match found" was misplaced as it implies that searchAPI failed, while that's not the only reason for the catch handler to be reached. Instead, the better pattern would be

function searchAPI(name) {
    …
    return Promise.reject(new Error("No match found"));
    //                              ^^^^^^^^^^^^^^^^ error message (or error code)
}   //                              thrown exactly where the error actually occurred

searchAPI(name).then(data => {
    let filtereddowndata = data.filter(item =>
        item.title.toLowerCase().includes(name.LowerCase())
    )
    …
}, err => { // <- second `then` argument
    console.log("Error from searchAPI", err);
});
// would now cause an unhandled rejection about the LowerCase method call

You can combine this with a catch handler of course:

searchAPI(name).then(data => {
    let filtereddowndata = data.filter(item =>
        item.title.toLowerCase().includes(name.LowerCase())
    )
    …
}, err => { // <- second `then` argument
    console.log("Error from searchAPI", err);
}).catch(err => {
    console.error("Error from promise callback", err);
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375