Подтвердить что ты не робот

Можно ли перехватывать исключения, вызванные асинхронным обратным вызовом JavaScript?

Есть ли способ отловить исключения в обратных вызовах JavaScript? Это вообще возможно?

Uncaught Error: Invalid value for property <address>

Вот 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);
}​
4b9b3361

Ответ 1

Причина, по которой он не поймает ничего в вашем примере, заключается в том, что после вызова обратного вызова geocode() блок try/catch завершен. Поэтому обратный вызов geocode() выполняется за пределами области try и, таким образом, не улавливается им.

Насколько я знаю, невозможно исключить исключения, вызванные обратными вызовами JavaScript (по крайней мере, не в прямом смысле).

Ответ 2

Да, вы можете переопределить поведение по умолчанию window.onerror:

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

Ответ 3

Вы действительно можете поймать исключения, которые срабатывают в функции обратного вызова JavaScript.

Ключ состоит в том, чтобы настроить блок try/catch в коде обратного вызова, поскольку любые блоки try/catch вне кода обратного вызова уже вышли к моменту выполнения кода обратного вызова. Поэтому, пока ваш блок try/catch выше не сможет поймать какие-либо исключения, которые будут вызваны при вызове функции обратного вызова, вы все равно можете сделать что-то вроде этого:

// 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!");
      }
   }
);

и вы сможете зафиксировать исключение, когда оно будет выбрано. Я не был на 100% уверен, будет ли это так или нет, поэтому я написал несколько тестовых кодов для проверки. Исключение фиксируется, как ожидалось, в браузере Chrome 19.0.1055.1.

Ответ 4

Я обнаружил ошибку с помощью обезьян, исправляющих журналы консоли.

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);
    }
}

Ответ 5

Согласно всем ответам, try/catch + callback установлен в другом контексте, но тогда - как бы вы объяснили, как работает этот код try/catch?

function doSomeAsynchronousOperation(cb) {
  cb(3);
}

function myApiFunc() {
  /*
   * This pattern does NOT work!
   */
  try {
    doSomeAsynchronousOperation((err) => {
      if (err) {
        console.log('got here');
        throw err;
      }

    });
  } catch (ex) {
    console.log(ex);
  }
}

myApiFunc();

Ответ 6

Здесь мой подход:

// 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 :(
}