aphilas
aphilas

Reputation: 2452

How to catch an error thrown in XMLHttpRequest's onload method

I am throwing an exception from the onload method of my XMLHttpRequest object. However I am unable to catch that error using a try catch block.

I have the following code in my _fetch(url, callback) function:

const xhr = new XMLHttpRequest()

xhr.onload = function () {
  if (xhr.readyState === xhr.DONE) {
    // if (xhr.status === 200) callback(xhr.response)

    // throw a 'custom' error if the server responds with 501
    if (xhr.status === 501) throw new Error('Answer not found') /
  }
}

// rest of the fn

Then, I am using the _fetch function:

try {
  _fetch(endPoint, response => console.log(response))
} catch (error) { // error not caught
  console.log(error)
}

However, the error is not caught and instead an error is thrown — Uncaught Error: Answer not found

What I have tried:

So, how can I catch that error?

To try out the full code, check out this fiddle.


Why do you need to throw the error in the onload method?

I am getting data from a certain API, and due to some restriction, I can't use fetch. I am using XMLHttpRequest instead. The server responds with the error code 501 - Not Implemented if the query I have sent cannot be answered. Thus I need to pick out that error code, and carry out some functionality.

Obviously, there are other possible ways to achieve my end goal, but I'm finding it hard to wrap my head around why this won't work. I have read up on both throw and XMLHttprequest but I may have a misunderstanding of how one of them works.

Upvotes: 4

Views: 5074

Answers (2)

Marcus Parsons
Marcus Parsons

Reputation: 1803

You absolutely can use fetch to make this not only easier on yourself, but to work with the errors. JSFiddle link below this code.

const url = `http://api.wolframalpha.com/v1/result?appid=H2R834-AUAJXG9KRV&i=%3F`
fetch(`https://cors-anywhere.herokuapp.com/${url}`)
.then(res => {
    console.log(res.status)
    if (res.status == 200) {
        return res.json()
    }
    else if (res.status == 501) {
        throw new Error("Answer not found")
    }
    else {
        throw new Error("Some other status code")
    }
})
.then(json => { 
    console.log(json) 
})
.catch(err => { 
    console.error(err)
})

https://jsfiddle.net/mparson8/ug1hoks8/9/

Upvotes: 5

blackening
blackening

Reputation: 953

While you can use a library to make your life easier,

XMLHttpRequest onXXXX are actually event handlers, onload being only one of many possible events. The full list is here: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Events

In this case, you have a missing error handler:

xhr.onerror( ... )

Also, if you have access to a modern browser, please use xhr.addEventListener('load'|'error'|..., ... ) instead. This actually allows multiple handlers, removing handlers, etc.


Regarding your sample code:

function _fetch(url, callback)


const xhr = new XMLHttpRequest()

xhr.onload = function () {
  if (xhr.readyState === xhr.DONE) {
    // if (xhr.status === 200) callback(xhr.response)

    // throw a 'custom' error if the server responds with 501
    if (xhr.status === 501) throw new Error('Answer not found')
    // This can never be caught because async functions break the stack.
    // Intuition: If you can't return it, you can't throw either.
  }
}

// rest of the fn

Then, I am using the _fetch function:

try {
  _fetch(endPoint, response => console.log(response))
} catch (error) { // error not caught
  console.log(error)
}

In this case, you need to modify the fetch's callback to use two parameters, in a similar style to node.js

In particular: _fetch(endPoint, (err, resp) => ... )


xhr.onload = function () {
  if (xhr.readyState === xhr.DONE) {
    // if (xhr.status === 200) callback(null, xhr.response)

    // throw a 'custom' error if the server responds with 501
    if (xhr.status === 501) callback(new Error('Answer not found'), null);
  }
}

Of course, the smart way is to use promises (or a library). Ensure you call either resolve or reject, at least once.

function _fetch(endpoint, callback) {
   return new Promise( (resolve, reject) => {
      xhr.onload = function () {
        if (xhr.readyState === xhr.DONE) {
        // if (xhr.status === 200) resolve(xhr.response)

        // throw a 'custom' error if the server responds with 501
        if (xhr.status === 501) reject(new Error('Answer not found'));
        }
      }

   });
}

This allows you to use it as follows:

_fetch(endpoint)
.then ( res => console.log('result', res) )
.catch( e => console.log('error', e);

Upvotes: -1

Related Questions