是否可以捕获JavaScript异步回调中抛出的异常?
有没有办法捕获JavaScript回调中的异常?有可能吗是否可以捕获JavaScript异步回调中抛出的异常?,javascript,google-maps,exception,callback,Javascript,Google Maps,Exception,Callback,有没有办法捕获JavaScript回调中的异常?有可能吗 Uncaught Error: Invalid value for property <address> 在您的示例中,它不会捕获任何内容的原因是,一旦调用了geocode()回调,try/catch块就结束了。因此,geocode()回调在try块的范围之外执行,因此它无法捕获 据我所知,捕获JavaScript回调中抛出的异常是不可能的(至少,不是以任何直接的方式)。您确实可以捕获JavaScript回调函数中触发的异常
Uncaught Error: Invalid value for property <address>
在您的示例中,它不会捕获任何内容的原因是,一旦调用了
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%确定是否会是这样,所以我写了一些测试代码来验证。在Chrome 19.0.1055.1开发版上按预期捕获异常。是的,您可以覆盖以下默认行为:
我通过修补控制台日志检测到错误
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+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();
如果您可以使用Promissions和async/await,则可以解决此问题,如下面的示例代码所示:
async 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);
};
});
});
}
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);
}
@anewb,给Daniels一个答案√问题是“这可能吗?”这是一个很好的答案,@BlakeRegalia.Logical,这正是我开始研究这个问题时所担心的。我遇到了这样一种情况:我无法控制的代码抛出一个我需要捕获的异常,但我不能,因为它是异步的……如果异常不是在回调代码中抛出的,而是由异步函数抛出的,会发生什么。异步函数在其处理过程中的某个点抛出错误,这意味着我们的try-catch都不会捕获它。我目前正面临这个问题。让我知道你认为可以做什么。这个答案是错误的。抛出由异步线程中的
a.b.c.f()
函数完成。换句话说,您的回调甚至不会被调用,因为回调之前有一个错误。只有当您的回调函数通过调用实现的函数进行协作时,实现者决定将错误转移到您的回调函数时,这个答案才是正确的。@Pacerier问题是,您能否在实际回调中捕获异常。如果没有调用回调,那么这就超出了这个问题的范围。@Pacier接受的答案说“不可能捕获JavaScript回调中抛出的异常”也是错误的。因此,这个函数是一个有用的附加函数。它之所以有效,是因为您没有异步调用回调函数。如果您这样做(例如使用setTimeout()
),它将失败。
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();
async 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);
};
});
});
}
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);
}