0

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>
BenMorel
  • 34,448
  • 50
  • 182
  • 322

1 Answers1

1

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" );
    });
}
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • Thanks Arun, sorry for the late reply (xmas and all..) I'll have to study your example a bit, but my initial response is why this would help me, I'm not looking for a try/catch within the response of the ajax call, but i'm looking for wrapping the ajax call in a throw/catch and catching any throw's from it's responses. – Jochem Van Der Spek Dec 28 '12 at 10:55
  • @JochemVanDerSpek It will not work like that with an `ajax` call. An ajax call is is a async call which means that, we do not know when the request will finish. – Arun P Johny Dec 29 '12 at 03:27
  • I'm sorry, but that's not what async means. The 'finish' of any call can be ill-determined. Async means it's executed in a different thread, and hence, the try is in one thread and the throw in another. this cannot be reconsiled. see user1321471's answer. – Jochem Van Der Spek Dec 29 '12 at 23:09
  • 1
    @JochemVanDerSpek Sorry, Javascript is mostly considered as a single threaded application, ie at any point of time only one piece of script will be executed. So it is not about the async call getting executed in another thread. http://www.nczonline.net/blog/2010/08/10/what-is-a-non-blocking-script/ / http://stackoverflow.com/questions/7575589/how-does-javascript-handle-ajax-responses-in-the-background / http://stackoverflow.com/questions/6659108/what-happens-in-javascript-when-an-ajax-call-returns-while-the-script-is-executi – Arun P Johny Dec 30 '12 at 02:36
  • thanks for your links ! *but* now I'm back to not understanding why there would be no way to do what i want. I have two questions for you, could you dream up of any other way to catch a throw from a callback from an ajax async call ? and do you know of any centralised resource (aka a book) that explains in details the implementation and execution models of browsers ? I'd really like to know the gritty details here.. – Jochem Van Der Spek Dec 31 '12 at 08:51
  • Reading a bit further, it seems really impossible to do this as the callback is called in the context of the event loop outside my script, right ? – Jochem Van Der Spek Dec 31 '12 at 08:58
  • @JochemVanDerSpek, Yes you are right. It is not possible to handle the case as you want since the executions are happening in different contexts. – Arun P Johny Dec 31 '12 at 09:19
  • Thanks Arun, for clearing that up. any chance of you knowing about a good resource on the implementation and execution models of browsers ? – Jochem Van Der Spek Dec 31 '12 at 10:24
  • @JochemVanDerSpek Sorry, just don't know any resource, just search you may find something online – Arun P Johny Dec 31 '12 at 10:42