是否可以捕获 JavaScript 异步回调中抛出的异常?

IT技术 javascript google-maps exception callback
2021-01-31 00:45:19

有没有办法在 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);
}​
6个回答

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

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

问题是“这甚至可能吗?” 这是一个很好的答案,@BlakeRegalia。
2021-03-24 00:45:19
@anewb,给丹尼尔斯一个√
2021-03-30 00:45:19
合乎逻辑,这正是我开始研究这个问题时所担心的。我遇到了一个我无法控制的代码抛出一个我需要捕获的异常的情况,但我不能,因为它是异步的......
2021-04-03 00:45:19

是的,您可以覆盖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; 
};
注意:特定于浏览器环境。不会在服务器端(NodeJS)工作。
2021-03-18 00:45:19

您确实可以捕获在 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 dev 上按预期捕获异常。

这个答案是错误的throw 是由a.b.c.f()异步线程中函数完成的换句话说,您的回调甚至没有被调用,因为在您的回调之前存在错误。只有当您的回调函数通过调用会向您的回调函数抛出错误的已实现函数进行协作时,实现者决定将该错误转移到您的回调函数,此答案才是正确的。
2021-03-16 00:45:19
如果异常不是在回调代码中抛出而是由异步函数抛出会发生什么。async 函数在其处理过程中的某个时刻抛出错误,这意味着我们的 try catch 不会捕获它。我目前正面临这个问题。让我知道你认为可以做什么。
2021-03-19 00:45:19
@Pacerier 接受的答案在说“不可能捕获 JavaScript 回调中抛出的异常”时也是错误的。因此,这是一个有用的附加项。
2021-03-22 00:45:19
@Pacerier 问题是您能否在实际回调中捕获异常。如果没有调用回调,那么这超出了这个问题的范围。
2021-03-23 00:45:19

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

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

如果可以使用 Promises 和 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);
}