Можно ли перехватывать исключения, вызванные асинхронным обратным вызовом 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);
}
Ответы
Ответ 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 :(
}