Skip to content

Commit 484287d

Browse files
Ensure Ajax.activeRequestCount decrements even if an exception is thrown in an onComplete callback. (close prototypejs#324)
1 parent 6192914 commit 484287d

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

src/prototype/ajax/request.js

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* In the optional `options` hash, you usually provide an `onComplete` and/or
1111
* `onSuccess` callback, unless you're in the edge case where you're getting a
1212
* JavaScript-typed response, that will automatically be `eval`'d.
13-
*
13+
*
1414
* For a full list of common options and callbacks, see "Ajax options" heading
1515
* of the [[Ajax section]].
1616
*
@@ -23,71 +23,71 @@
2323
* });
2424
*
2525
* ##### Request life-cycle
26-
*
26+
*
2727
* Underneath our nice requester objects lies, of course, `XMLHttpRequest`. The
2828
* defined life-cycle is as follows:
29-
*
29+
*
3030
* 1. Created
3131
* 2. Initialized
3232
* 3. Request sent
3333
* 4. Response being received (can occur many times, as packets come in)
3434
* 5. Response received, request complete
35-
*
35+
*
3636
* As you can see under the "Ajax options" heading of the [[Ajax section]],
3737
* Prototype's AJAX objects define a whole slew of callbacks, which are
3838
* triggered in the following order:
39-
*
39+
*
4040
* 1. `onCreate` (this is actually a callback reserved to [[Ajax.Responders]])
4141
* 2. `onUninitialized` (maps on Created)
4242
* 3. `onLoading` (maps on Initialized)
4343
* 4. `onLoaded` (maps on Request sent)
4444
* 5. `onInteractive` (maps on Response being received)
4545
* 6. `on`*XYZ* (numerical response status code), onSuccess or onFailure (see below)
4646
* 7. `onComplete`
47-
*
47+
*
4848
* The two last steps both map on *Response received*, in that order. If a
4949
* status-specific callback is defined, it gets invoked. Otherwise, if
5050
* `onSuccess` is defined and the response is deemed a success (see below), it
5151
* is invoked. Otherwise, if `onFailure` is defined and the response is *not*
5252
* deemed a success, it is invoked. Only after that potential first callback is
5353
* `onComplete` called.
54-
*
54+
*
5555
* ##### A note on portability
56-
*
56+
*
5757
* Depending on how your browser implements `XMLHttpRequest`, one or more
5858
* callbacks may never be invoked. In particular, `onLoaded` and
5959
* `onInteractive` are not a 100% safe bet so far. However, the global
6060
* `onCreate`, `onUninitialized` and the two final steps are very much
6161
* guaranteed.
62-
*
62+
*
6363
* ##### `onSuccess` and `onFailure`, the under-used callbacks
64-
*
64+
*
6565
* Way too many people use [[Ajax.Request]] in a similar manner to raw XHR,
6666
* defining only an `onComplete` callback even when they're only interested in
6767
* "successful" responses, thereby testing it by hand:
68-
*
68+
*
6969
* // This is too bad, there's better!
7070
* new Ajax.Request('/your/url', {
7171
* onComplete: function(response) {
7272
* if (200 == response.status)
7373
* // yada yada yada
7474
* }
7575
* });
76-
*
76+
*
7777
* First, as described below, you could use better "success" detection: success
7878
* is generally defined, HTTP-wise, as either no response status or a "2xy"
7979
* response status (e.g., 201 is a success, too). See the example below.
80-
*
80+
*
8181
* Second, you could dispense with status testing altogether! Prototype adds
8282
* callbacks specific to success and failure, which we listed above. Here's
8383
* what you could do if you're only interested in success, for instance:
84-
*
84+
*
8585
* new Ajax.Request('/your/url', {
8686
* onSuccess: function(response) {
8787
* // yada yada yada
8888
* }
8989
* });
90-
*
90+
*
9191
* ##### Automatic JavaScript response evaluation
9292
*
9393
* If an Ajax request follows the _same-origin policy_ **and** its response
@@ -305,9 +305,10 @@ Ajax.Request = Class.create(Ajax.Base, {
305305

306306
try {
307307
(this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
308-
Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
309308
} catch (e) {
310309
this.dispatchException(e);
310+
} finally {
311+
Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
311312
}
312313

313314
if (state == 'Complete') {

test/unit/tests/ajax.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,23 @@ suite("Ajax", function () {
104104
}, 1000);
105105
});
106106

107+
test("activeRequestCount decrements when an exception occurs in a handler", function (done) {
108+
109+
new Ajax.Request('/fixtures/hello.js', {
110+
method: 'GET',
111+
onComplete: function () {
112+
assert.equal(1, Ajax.activeRequestCount);
113+
throw new Error('test');
114+
}
115+
});
116+
117+
setTimeout(function () {
118+
assert.equal(0, Ajax.activeRequestCount);
119+
done();
120+
}, 1000);
121+
122+
});
123+
107124
suite('Updater', function () {
108125

109126
setup(function () {

0 commit comments

Comments
 (0)