I'm having some trouble catching a throw from a callback in an Ajax callback. I've made a minimal test case here (code below).
In the init()
function I create a new object of class ResourceLoader
and try to get http://www.jvanderspek.com. via $.ajax. This succeeds and the ResourceLoader.prototype.onDone
function is called. Now for the sake of argument I'd like to throw an error there, and catch it at the top of my calling tree, in the init();
function, but alas, the throw is not caught. Now, this has probably to do with Ajax being executed in a different thread and the throw being called when the execution is already outside the try block, but how can I remedy it? Perhaps I'm mistaken about the cause, but then the bonus question is, why does this happen at all?
<html>
<head>
<title>testbed</title>
<script src="http://code.jquery.com/jquery-1.8.3.js" type="text/javascript"></script>
</head>
<body onload="init();">
</body>
<script type="text/javascript">
init = function() {
ResourceLoader = function(){}
ResourceLoader.prototype.load = function(){
var done = $.proxy(this.onDone, this);
$.ajax({
url: "http://www.jvanderspek.com",
}).done(done);
}
ResourceLoader.prototype.onDone = function() {
console.log( "onDone");
throw(new Error());
}
var rl = new ResourceLoader();
try {
rl.load();
}
catch(error){
window.alert( "Error caught" );
}
}
</script>
</html>
It is because Ajax uses asynchronous execution model.
In an asynchronous call after the ajax call is made the execution of the code will continue without waiting for the response to comeback. When the response comes back from the server the success/failure callback will be called.
In your case the rl.load();
call will return as soon as the request to the server is sent (ie: before the error is thrown) that is why the catch block is not working.
A possible dirty solution to your problem is to pass an additional parameter async: false
to the ajax call. But it fails the whole purpose of Ajax call since it will block the user experience till the ajax call is completed. I've not tested this solution, possibly you can try this. I'll not recommend this one to any one, but as part of understanding about Ajax probably you can try this.
Another solution is to pass a error callback to the load()
method, and do what ever you want in case of a failure in that callback.
Ex:
init = function() {
ResourceLoader = function(){}
ResourceLoader.prototype.load = function(errorCallback){
var done = $.proxy(this.onDone, this);
$.ajax({
url: "http://www.jvanderspek.com",
}).done(function(){
try{
console.log( "onDone");
throw(new Error());
}catch(error){
errorCallback(error)
}
});
}
var rl = new ResourceLoader();
rl.load(function(error){
window.alert( "Error caught" );
});
}