是否有可能捕获 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);
}​
35518 次浏览

在您的示例中不捕获任何内容的原因是,一旦调用了 geocode()回调函数,try/catch块就结束了。因此,geocode()回调在 try块的范围之外执行,因此不能被它捕获。

据我所知,不可能捕获 JavaScript 回调中抛出的异常(至少不是以任何直接的方式)。

您确实可以捕获在 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% 确定是否会出现这种情况,所以我编写了一些测试代码来验证。这个异常在 Chrome19.0.1055.1 dev 中被捕获。

是的,您可以覆盖 一个错误的默认行为:

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

我通过修补控制台日志检测到了错误。

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

我的方法是:

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

根据所有的答案,try/catch + 回调是在不同的上下文中设置的,但是-您如何解释这段代码 try/catch working?

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

如果你可以使用承诺,它可以解决,如下面的示例代码所示:

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

执行函数并使用 catch ()捕获错误:

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

执行函数并使用 sync/wait 捕获错误:

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