0

With Javascript, I am trying to make a call to an external API when a form is submited. I am using promises in order to set follow up actions once the call is done and to catch eventual errors.

This is where my problem is, even if I think I am catching my errors correctly, the console throws an

Uncaught (in promise) error : [The error I throw]

I do not understand why.

Here is a minimal version of my code which would reproduce the error when the refreshToken is expired :

try {
        functionGeneratingTheError();
    } catch (error) {
        doSomethingElse();
    }
function functionGeneratingTheError() {
    
    var getTokenCallPayload = {
        "client_id" : clientId,
        "client_secret" : clientSecret,
        "refresh_token" : refreshToken,
        "grant_type" : "refresh_token"
    };
    var getTokenCallOptions = {
        "method" : "POST",
        "body" : JSON.stringify(getTokenCallPayload),
        "muteHttpExceptions" : false
    };
    fetch(tokenURL, getTokenCallOptions)
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error");
        }
    })
    .then(data => {
        doSomething();
    })  
    .then(response=> {
        doSomethingAgain();
    }) 
    .catch(error => {
        throw error;
    });
}

If I understand correctly, when the fetch is a bad request, it should throw the error "Error" which should then be caught in the first catch and run the doSomethingElse() function. However, instead of doing that, I get this error in the browser console "Uncaught (in promise) Error: Error"

What am I doing wrong ?

I have tried including the fetch in a try{}catch(){} but it doesn't change anything.

I also tried not throwing the error and directly call my doSomethingElse() function, but then the following .then fails because data is undefined.

  • Maybe because `fetch` is asynchronous. The code in `then` runs after `functionGeneratingTheError` has finished executing. – Fractalism Jan 31 '23 at 13:31
  • The first block of code is executed without any error i.e. no exception is caught. Error is only caught at catch method of promise because of asynchronous nature of promise. If you want the error caught in try.. catch then use async... await – Vignesh Pandi Jan 31 '23 at 13:33
  • 1
    1. ` .catch(error => { throw error; });` Is essentially the same noop as [`.then(function(a){ return a; })`](https://stackoverflow.com/questions/41089122/is-thenfunctiona-return-a-a-no-op-for-promises). You're catching and rethrowing the exception. Which is the same as not having the `.catch()` handler at all. 2. `fetch()` is asynchronous. You need to use `try/catch` with `await` on the promise to catch rejections as errors. 3. To that effect `functionGeneratingTheError` should actually be returning the promise. Right now, it's not. There is no way to handle the async failure. – VLAZ Jan 31 '23 at 13:34
  • @VLAZ do you mean that my fonctionGeneratingTheEroor should return the fetch ? – Quentin Escaron Jan 31 '23 at 14:06
  • Yes. Otherwise right now it returns `undefined`. And doesn't throw errors, either. – VLAZ Jan 31 '23 at 14:10
  • Alright, so I added : - return on the fetch - await on the call to functionGeneratingTheError () - async on the function with the try{}catch calling the functionGeneratingTheError and it worked. Thank you ! – Quentin Escaron Jan 31 '23 at 15:40

1 Answers1

0

Change your functionGeneratingTheError function to return the chained promise like below:

function functionGeneratingTheError() {
    
    var getTokenCallPayload = {
        "client_id" : clientId,
        "client_secret" : clientSecret,
        "refresh_token" : refreshToken,
        "grant_type" : "refresh_token"
    };
    var getTokenCallOptions = {
        "method" : "POST",
        "body" : JSON.stringify(getTokenCallPayload),
        "muteHttpExceptions" : false
    };

    return
    fetch(tokenURL, getTokenCallOptions)
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error");
        }
    })
    .then(data => {
        doSomething();
    })  
    .then(response=> {
        doSomethingAgain();
    }) 
    .catch(error => {
        throw error;
    });
}

And then await it in your calling code by wrapping the calling code inside an async self invoking function like so:

(async function() {
try {
        await functionGeneratingTheError();
    } catch (error) {
        doSomethingElse();
    }
})();

You can read more about async/await here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

  • I added - return on the fetch - await on the call to functionGeneratingTheError () - async on the function with the try{}catch calling the functionGeneratingTheError and it worked. I did not need to make the function self invoking, was there a necessity to do this ? Thank you ! – Quentin Escaron Jan 31 '23 at 15:41
  • After correcting as you suggested I tried to improve on my code to replace .then sequences with await calls. The new code looks like this : `async function functionGeneratingTheError() { var response = await fetch(tokenURL, getTokenCallOptions); if (response.ok) { var data = await response.json(); var response2 = await doSomething(); var response3 = await doSomethingAgain(); } else { throw new Error("Error"); } }` But if I have an error in the response 2 or 3, the error is also uncaught (in promise). What am I doing wrong ? – Quentin Escaron Jan 31 '23 at 17:29
  • sorry if this not the right place to post this follow up question (I did not find where to put this in the help center) – Quentin Escaron Jan 31 '23 at 17:36
  • @QuentinEscaron with the pre JavaScript ES2020, you can only await a Promise inside an async function. Hence I had wrapped your calling logic inside an async function since it seemed like it was not within any function any all (assuming your JavaScript engine is pre ES2020) – Kagiso Marvin Molekwa Jan 31 '23 at 18:00