76

Is there a way to catch exceptions in JavaScript callbacks? Is it even possible?

Uncaught Error: Invalid value for property <address>

Here is the jsfiddle: http://jsfiddle.net/kjy112/yQhhy/

try {
    // this will cause an exception in google.maps.Geocoder().geocode() 
    // since it expects a string.
    var zipcode = 30045; 
    var map = new google.maps.Map(document.getElementById('map_canvas'), {
        zoom: 5,
        center: new google.maps.LatLng(35.137879, -82.836914),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    // exception in callback:
    var geo = new google.maps.Geocoder().geocode({ 'address': zipcode }, 
       function(geoResult, geoStatus) {
          if (geoStatus != google.maps.GeocoderStatus.OK) console.log(geoStatus);
       }
    );
} catch (e) {
    if(e instanceof TypeError)
       alert('TypeError');
    else
       alert(e);
}​

6 Answers 6

83

The reason it won't catch anything in your example is because once the geocode() callback is called, the try/catch block is over. Therefore the geocode() callback is executed outside the scope of the try block and thus not catchable by it.

As far as I know, it is not possible to catch exceptions thrown in JavaScript callbacks (at least, not in any straightforward manner).

Sign up to request clarification or add additional context in comments.

3 Comments

@anewb, give Daniels answer a √
The question is "Is it even possible?" and this is a good answer, @BlakeRegalia.
Logical and just what I feared when I started looking at this problem. I'm stuck with a case where code I don't control throws an exception I need to catch, but I can't because it's async...
43

Yes, you can override the default behaviour of window.onerror:

window.onerror = function(message, file, lineNumber) {
  // all errors will be caught here
  // you can use `message` to make sure it's the error you're looking for
  // returning true overrides the default window behaviour
  return true; 
};

1 Comment

Note: Specific to browser environment. Will not work server-side (NodeJS).
16

You can indeed catch exceptions that fire within a JavaScript callback function.

The key is to set up the try/catch block within the callback code, as any try/catch blocks outside the callback code will have already exited by the time the callback code is executed. So while your try/catch block above won't be able to catch any exceptions that get thrown when the callback function is called, you can still do something like this:

// this will cause an exception ing google.maps.Geocoder().geocode() 
// since it expects a string.
var zipcode = 30045; 
var map = new google.maps.Map(document.getElementById('map_canvas'), {
    zoom: 5,
    center: new google.maps.LatLng(35.137879, -82.836914),
    mapTypeId: google.maps.MapTypeId.ROADMAP
});
// exception in callback:
var geo = new google.maps.Geocoder().geocode({ 'address': zipcode }, 
   function(geoResult, geoStatus) {
      try {
          if (geoStatus != google.maps.GeocoderStatus.OK) console.log(geoStatus);
      } catch(e){
          alert("Callback Exception caught!");
      }
   }
);

and you'll be able to capture the exception when it is thrown. I wasn't 100% sure whether that would be the case or not, so I wrote some test code to verify. The exception is captured as expected on Chrome 19.0.1055.1 dev.

4 Comments

What happens if the exception was not thrown in callback code but rather by the async function. The async function throws error at some point in its processing which means none of our try catch will catch it. I am currently facing this issue. Let me know what you think can be done.
This answer is wrong. The throw is done by the a.b.c.f() function in the asynchronous thread. In other words your callback doesn't even get called because there is an error before your callback. This answer will only be right if the implementer decides to transfer that error to your callback function when your callback function cooperates by calling the implemented function which would throw the error to your callback function.
@Pacerier the question was can you catch an exception in the actual callback. The if callback isn't called, then that is outside the scope of this question.
@Pacerier the accepted answer is also wrong in saying "it is not possible to catch exceptions thrown in JavaScript callbacks". Thus this one is an useful additionnal.
5

If you can use Promises, it can be solved as shown in sample code below:

function geocode(zipcode) {
  return new Promise((resolve, reject) => {
    const g = new google.maps.Geocoder().geocode({ 'address': zipcode },  function(geoResult, geoStatus) {
      if (geoStatus != google.maps.GeocoderStatus.OK) {
        reject(new Error("Callback Exception caught"));
      } else {
        resolve(g);
      };
    });
  });
}

Executing the function and catching the error using catch():

geocode(zipcode)
  // g will be an instance of new google.maps.Geocoder().geocode..
  .then( g => console.log ( g ) )
  .catch( error => console.log( error ) );

Executing the function and catching the error using async/await:

try {
  // g will be an instance of new google.maps.Geocoder().geocode..
  // you can resolve with desired variables
  const g = await geocode(zipcode);
} catch( e ) {
  console.log(e);
}

1 Comment

I find it funnt that this is not the accepted answer
-1

I have detected the error by monkey patching the console logs.

if(window.console && console.error){
    var old = console.error;
    console.error = function(){
        if(arguments[0].indexOf('Google Maps API error')!=-1){
            alert('Bad Google API Key '+ arguments[0]);
        }
        Array.prototype.unshift.call(arguments);

        old.apply(this, arguments);
    }
}

Comments

-1

Here's my approach:

// the purpose of this wrapper is to ensure that any
// uncaught exceptions after a setTimeout still get caught
function callbackWrapper(func) {
    return function() {
        try {
            func();
        } catch (err) {
            // callback will reach here :)
            // do appropriate error handling
            console.log("error");
        }
    }
}

try {
    setTimeout(callbackWrapper(function() {throw "ERROR";}), 1000);
} catch (err) {
    // callback will never reach here :(
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.