-1

I am defining a global jQuery error handler for status codes 500 (retry mechanism with some message, when retry exhausted). I'd like to override any .fail() promise that might have been added to an $.ajax request. My code below:

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">

            function call() {

                $.ajax({
                  url: '/rest/api/v1/some_errorneous_parth',
                  retryCount:3,
                  method: 'GET'
                }).done(function(data){
                    console.log(data);
                }).fail(function() {
                    console.log("should not print");
                });
            }

            $(document).ready(function () {
                $.ajaxSetup({
                    retryCount: 3,
                    error: function retry(response) {
                        if(response.statuscode === 500) {
                            if(--this.retryCount){
                                $.ajax(this);
                            }
                            else {
                                console.log("sorry, i've 'tried everything");
                            }
                        }
                    }
                });
            });
        </script>
    </head>
    <body>
        <input type="button" onclick="call()" value="submit"/>
    </body>
</html> 

I'd like the should not print to not be printed if the server returns 500 until the retry count gets exhausted.

LIvanov
  • 1,126
  • 12
  • 30
  • `fail()` is not being added to the ajax request. It is invoking the fail method off of the deferred returned from the ajax call. – Taplar Apr 30 '18 at 18:42
  • So can I somehow change the state of the deferred return, so that the fail doesn't get called. – LIvanov Apr 30 '18 at 18:43
  • Promises/deferreds are only resolved/rejected once. Once they are done so, as far as I am aware, their state cannot be flipped. – Taplar Apr 30 '18 at 18:44

1 Answers1

1

A few observations ...

jQuery documentation says of .ajaxSetup()

... we strongly recommend against using this API.

The documentation also says :

All subsequent Ajax calls using any function will use the new settings, unless overridden by the individual calls, until the next invocation of $.ajaxSetup().

Therefore your expectation that an option in an $.ajax request be overridden by the corresponding option established in ajaxSetup is back-to-front. Overriding works the other way round.

In any case, .done() and .fail() options don't obey the "overridden by the individual calls" rule. A fail callback established in ajaxSetup and a fail callback established in an individual call will (on error) BOTH fire - in that order. The documentation provides no warning about this.

Arbitrary options like retryCount will be ignored.

Retries need to be orchestrated by some other means - see eg Promise Retry Design Patterns

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • This is all good, unless you have a legacy, unsystematic codebase, where there is a global handler `$.ajaxSetup` that adds an authorization header. Then, all other calls are performed with `$.ajax()`. In fact, my real case is not retry, but JWT refresh, when expired. Therefore, I need any `$.ajax` call to not have `.fail()` executed, when a `401` is thrown and a subsequent JWT refresh succeeds `$.ajaxSetup({ error: when 401})` – LIvanov Apr 30 '18 at 19:45
  • Under those circumstances, the only workaround I can think of would be to load a second copy of jQuery, in which `jQuery.ajaxSetup()` has not been called. [`jQuery.noConflict()`](https://api.jquery.com/jQuery.noConflict/) will allow two copies to co-exist. In the code under your control, you then have the choice of calling the original `$.ajax()` or the second copy, say `$$.ajax()`. – Roamer-1888 Apr 30 '18 at 20:04