AJAX exception handling

246 views
Skip to first unread message

Glenn Maynard

unread,
May 13, 2009, 10:40:49 PM5/13/09
to prototype-s...@googlegroups.com
Exceptions inside AJAX handlers are sent to onException and then
swallowed. The behavior I think most people would expect is that if
they're not using any onException handlers, exceptions should be
raised normally, not silently discarded. That's the behavior I
want--for errors to always go to the error console, like all other
errors. (I can see the underlying reason for this behavior--so
callbacks are guaranteed to be called, even if one of them
misbehaves.)

I can work around this with a responder:

Ajax.Responders.register({
onException: function(request, exception) {
(function() { throw exception; }).defer();
}
});

The defer() is necessary to break out of Ajax.Responders.dispatch's
exception handler, which silently eats everything. This also has the
nice property that if multiple callbacks throw errors, the callback
chain isn't broken, but all of the errors are still shown. It's also
not dependant on responder order; if it's registered first, later
responders still run.

I'm not sure if throwing an exception outside of the context it was
originally thrown will confuse JS debuggers. (I don't use one; they
all destabilize FF badly for me.)

It would be nice to have this behavior by default. I suspect most
people who use Prototype AJAX have been bitten by this, and this
workaround is a bit obscure for people to have to discover on their
own.

--
Glenn Maynard

T.J. Crowder

unread,
May 14, 2009, 3:24:12 AM5/14/09
to Prototype & script.aculo.us
Hi,

> swallowed. The behavior I think most people would expect is that if
> they're not using any onException handlers, exceptions should be
> raised normally, not silently discarded.

I don't think they would, but more to the point, "raised normally"
*where*? In the normal case (asynchronous requests), the code that
initiated the request has long since completed. So unless you mean
raising exceptions to the browser (which doesn't seem like a good
idea, and can result in your script being terminated completely), I
don't see where it would get raised. And there's no standard for a
global exception catcher, is there? Some browsers have them, I think,
but I don't know of a standard for one. So even if Prototype raised
the exception globally, how would you handle it?

No, having a callback for exceptions makes sense to me. As with a
standard try/catch/finally block, your exception handling logic is
near (but not interspersed with) your mainline logic, which has proven
to be a fairly useful paradigm. (try = request, catch = onException,
finally = onComplete) Maybe there could be an argument for
synchronous requests to raise the exception out of the Ajax.Request
constructor, but I think it's trumped by having a uniform way of
handling exceptions for all Ajax requests (rather than different
mechanisms depending on whether you're doing a synchronous or async
request).

If you want to semi-globally handle all exceptions in Ajax requests,
as you show you can do it with a responder. If you want to semi-
globally handle all exceptions only in your own Ajax requests (and
not, say, Autocompleter's), a factory function readily handles setting
that up on each request.

function ajaxRequest(url, options) {
options = options || {};
options.onException = options.onException || yourGlobalHandler;
return new Ajax.Request(url, options);
}
--
T.J. Crowder
tj / crowder software / com
Independent Software Engineer, consulting services available

Glenn Maynard

unread,
May 14, 2009, 3:54:25 PM5/14/09
to prototype-s...@googlegroups.com
On Thu, May 14, 2009 at 3:24 AM, T.J. Crowder <t...@crowdersoftware.com> wrote:
> I don't think they would, but more to the point, "raised normally"
> *where*?  In the normal case (asynchronous requests), the code that
> initiated the request has long since completed.  So unless you mean
> raising exceptions to the browser (which doesn't seem like a good
> idea, and can result in your script being terminated completely), I
> don't see where it would get raised.  And there's no standard for a
> global exception catcher, is there?  Some browsers have them, I think,
> but I don't know of a standard for one.  So even if Prototype raised
> the exception globally, how would you handle it?

Errors in my code, when I havn't installed any error handler
explicitly, should be returned to the browser, to be displayed in the
usual error windows. If I want some other behavior, I'll install an
error handler (whether a try/catch block or, for Ajax.Request, an
onException handler). Discarding errors by default is very strange.

The exception should minimally be re-thrown if no onException
handlers, local or global, exist. Attached patch (not heavily tested)
shows what I mean.

> to be a fairly useful paradigm.  (try = request, catch = onException,
> finally = onComplete)  Maybe there could be an argument for

Errors in onComplete are also sent to onException, so I think this
mapping is a little off.

> If you want to semi-globally handle all exceptions in Ajax requests,
> as you show you can do it with a responder.  If you want to semi-

Sure, after figuring out why exceptions are disappearing, and then
figuring out how to get around that all-encompassing exception block
surrounding the responder. It's a lot of digging to get reasonable
default behavior.

--
Glenn Maynard

prototype-1.5-ajax-rethrow.diff

T.J. Crowder

unread,
May 14, 2009, 8:17:18 PM5/14/09
to Prototype & script.aculo.us
> Sure, after figuring out why exceptions are disappearing, and then
> figuring out how to get around that all-encompassing exception block
> surrounding the responder. It's a lot of digging to get reasonable
> default behavior.

Or, you know, read the documentation. ;-)

No, seriously, we'll have to agree to disagree on this. I'm just one
counterpoint to your statement that "most people" would expect
something else. I wouldn't. I expected, and quickly found when I
started using Prototype's Ajax stuff, exactly what's there. I find
the default behavior quite reasonable.

-- T.J. :-)
>  prototype-1.5-ajax-rethrow.diff
> < 1KViewDownload

Glenn Maynard

unread,
May 14, 2009, 8:38:27 PM5/14/09
to prototype-s...@googlegroups.com
On Thu, May 14, 2009 at 8:17 PM, T.J. Crowder <t...@crowdersoftware.com> wrote:
>> Sure, after figuring out why exceptions are disappearing, and then
>> figuring out how to get around that all-encompassing exception block
>> surrounding the responder.  It's a lot of digging to get reasonable
>> default behavior.
>
> Or, you know, read the documentation. ;-)

The documentation explains how to set exception handlers within AJAX.
It does not explain that if you don't set one, exceptions will be
silently ignored; to figure out why my callbacks were silently doing
nothing I had to trace the source. Nor does it explain how to force
exceptions to be propagated normally; delaying the exception in a
defer() is hardly obvious.

> No, seriously, we'll have to agree to disagree on this.  I'm just one
> counterpoint to your statement that "most people" would expect
> something else.  I wouldn't.  I expected, and quickly found when I
> started using Prototype's Ajax stuff, exactly what's there.  I find
> the default behavior quite reasonable.

You find the default behavior of silently ignoring all exceptions
reasonable? Seriously?

Please explain why it should not propagate exceptions normally when no
error handlers are set. You havn't given any rational explanation.
If you're using exception callbacks, then this has zero impact on you.

--
Glenn Maynard

T.J. Crowder

unread,
May 15, 2009, 4:47:11 AM5/15/09
to Prototype & script.aculo.us
Hi,

> Please explain why it should not propagate exceptions normally...

I don't see any point in continuing this. You feel quite strongly
about this and I'm unlikely to change your mind. I feel less strongly
about it, but you're not likely to change my mind either -- not that
it matters either way, as neither of us is a Core developer. :-) I
_do_ see your point about the absense of an onException handler being
somewhat analagous to the absense of a catch block.

Happy coding,
--
T.J. Crowder
tj / crowder software / com
Independent Software Engineer, consulting services available


Glenn Maynard

unread,
May 15, 2009, 4:06:48 PM5/15/09
to prototype-s...@googlegroups.com
On Fri, May 15, 2009 at 4:47 AM, T.J. Crowder <t...@crowdersoftware.com> wrote:
> I don't see any point in continuing this.  You feel quite strongly
> about this and I'm unlikely to change your mind.  I feel less strongly
> about it, but you're not likely to change my mind either -- not that
> it matters either way, as neither of us is a Core developer. :-)  I
> _do_ see your point about the absense of an onException handler being
> somewhat analagous to the absense of a catch block.

If you're not going to explain your opinion at all, then no, there's
no point in continuing this with you. You havn't offered a single
reason for why the errors should not be raised if no exception
handlers are set. Don't just assert your disagreement and then refuse
to explain it.

--
Glenn Maynard

rasmus

unread,
Jun 13, 2009, 7:41:05 PM6/13/09
to Prototype & script.aculo.us
Any news on this? I myself was confused with the way Prototype seems
to be swallowing exceptions without giving the developer a clue about
it.

As Glenn, I really feel that exceptions thrown from an ajax request
should somehow be propagated upwards if no explicit onException
(analogous to a catch in my mind) is provided.

However, something tells me that the reason this is not done is due to
the way ajax requests work. After an ajax request is sent, the js
interpreter will reach the end of any global try block long before the
ajax response returns. Hence, it does not make sense to propagate any
exceptions upwards in the call stack as suggested; when the function
provided via onComplete is executed there will be no sub routines in
the call stack.

Maybe this is the reason why no exceptions are thrown: you cannot
possible wrap the onComplete function with a global try/catch block as
it is called out of "normal" context.

No matter what, I'd like to hear a clarification from someone who
understands this better than I do :)

T.J. Crowder

unread,
Jun 14, 2009, 4:22:23 AM6/14/09
to Prototype & script.aculo.us
Hi,

> when the function
> provided via onComplete is executed there will be no sub routines in
> the call stack

Right (well, not very many). But if you look again a Glenn's
suggestion, he's saying that not having an onException handler in your
Ajax options is analogous to not having a try..catch block around you
code, so the exception would be raised to the browser. He
demonstrated that much the same could be achieved by raising the
exceptions via a defer (setTimeout). It doesn't provide nesting,
which I think is important, but it would make the exceptions not
silent in the absense of a handler, which was his goal.

I don't speak for the Core team, but I don't see it happening if none
of them have jumped into this thread so far.

FWIW,
--
T.J. Crowder
tj / crowder software / com
Independent Software Engineer, consulting services available


rasmus

unread,
Jun 14, 2009, 8:09:07 AM6/14/09
to Prototype & script.aculo.us
Thank you for your reply.

On Jun 14, 10:22 am, "T.J. Crowder" <t...@crowdersoftware.com> wrote:
>
> I don't speak for the Core team, but I don't see it happening if none
> of them have jumped into this thread so far.
>

Yeah, you are probably right. If they feel things are optimal as they
are, I really think the core team at least should consider updating
the docs, documenting this behavior with something like:
"If no onException is provided exceptions occur silently."

... and maybe even WHY it has been decided to do it like this.

It will spare a significant portion of new prototype users from being
confused about this.

T.J. Crowder

unread,
Jun 15, 2009, 3:34:27 AM6/15/09
to Prototype & script.aculo.us
Hi,

> I really think the core team at least should consider updating
> the docs

No harm in asking!
https://prototype.lighthouseapp.com/projects/8886-prototype/overview

> It will spare a significant portion of new prototype users from being
> confused about this.

I very much doubt that it's anything like a significant portion.

Happy coding,
--
T.J. Crowder
tj / crowder software / com
Independent Software Engineer, consulting services available


rasmus

unread,
Jun 17, 2009, 12:31:19 PM6/17/09
to Prototype & script.aculo.us
> No harm in asking!https://prototype.lighthouseapp.com/projects/8886-prototype/overview
>
Thank you for the reference.

I found this interesting ticket on the subject:
https://prototype.lighthouseapp.com/projects/8886/tickets/634-no-exception-on-error-in-oncreate-method-of-ajaxrequest

Tobie Langel, one of the core members, agrees that exceptions should
be rethrown in ajax callbacks instead of dieing silently.
Reply all
Reply to author
Forward
0 new messages