2010-09-09 1 views
51

Existe-t-il un moyen d'intercepter les exceptions dans les rappels JavaScript? Est-ce même possible?Est-il possible d'intercepter les exceptions lancées dans un rappel JavaScript asynchrone?

Uncaught Error: Invalid value for property <address> 

Voici le 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); 
}​ 

Répondre

61

La raison pour laquelle il ne sera pas attraper quoi que ce soit dans votre exemple est parce qu'une fois le rappel geocode() est appelé, le bloc try/catch est terminé. Par conséquent, le rappel geocode() est exécuté en dehors de la portée du bloc try et ne peut donc pas être intercepté par celui-ci. Pour autant que je sache, il n'est pas possible d'intercepter les exceptions lancées dans les rappels JavaScript (du moins, pas de manière directe).

+8

@anewb, donnez Daniels répondre à un √ – sbartell

+1

La question est "Est-il possible?" et c'est une bonne réponse, @BlakeRegalia. – mqsoh

+1

Logique et juste ce que je craignais quand j'ai commencé à regarder ce problème. Je suis coincé avec un cas où le code que je contrôle ne déclenche pas une exception que je dois attraper, mais je ne peux pas car c'est asynchrone ... –

14

Vous pouvez en effet intercepter des exceptions déclenchées par une fonction de rappel JavaScript.

La clé est de mettre en place le bloc try/catch dans le code de rappel, car tous les blocs try/catch en dehors du code de rappel auront déjà quitté au moment où le code de rappel est exécuté. Ainsi, alors que votre try/catch bloc ci-dessus ne sera pas en mesure de prendre des exceptions qui se Renvoyé lorsque la fonction de rappel est appelée, vous pouvez encore faire quelque chose comme ceci:

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

et vous serez en mesure de capturer l'exception quand il est jeté. Je n'étais pas sûr à 100% si ce serait le cas ou non, alors j'ai écrit un code de test pour vérifier. L'exception est capturée comme prévu sur Chrome 19.0.1055.1 dev.

+2

Que se passe-t-il si l'exception n'a pas été lancée dans le code de rappel fonction. La fonction async jette une erreur à un moment donné de son traitement, ce qui signifie qu'aucun de nos catch try ne l'attrape. Je suis actuellement confronté à ce problème. Dites-moi ce que vous pensez pouvoir faire. – faizan

+0

** Cette réponse est fausse **. Le lancement est effectué par la fonction 'a.b.c.f()' dans le thread asynchrone. En d'autres termes, votre callback n'est même pas appelé car il y a une erreur avant votre callback. Cette réponse ne sera correcte que si l'implémenteur décide de transférer cette erreur à votre fonction de rappel lorsque votre fonction de rappel coopère en appelant la fonction implémentée qui enverrait l'erreur à votre fonction de rappel. – Pacerier

+0

@Pacerier la question était peut-on attraper une exception dans le rappel réel. Si le callback n'est pas appelé, alors cela sort du cadre de cette question. – Brain2000

37

Oui, vous pouvez remplacer le comportement par défaut de 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; 
}; 
1

J'ai détecté l'erreur par singe patcher les journaux de la console.

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

Voilà mon approche:

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