after successful ajax retry no .done

2019-08-06 08:06发布

问题:

I'm making a request to a php file. The response is processed in .done(function(msg){}); and .fail this works fine. But sometimes the request gets an error. I made a retry for this. The retry also works. But if the first time fails and it is successful in de 2 or 3 try my request.done doesn't fire (in firebug I can see that is was successful)

My request:

    var request = $.ajax({    
                url:            "wcf.php",            
                type:           "POST",     
                dataType:       "xml",
                async:          false,
                timeout:        5000,
                tryCount:       0,
                retryLimit:     3,
                data:      { barcode: value, curPrxID: currentPrxID, timestamp: (new Date).getTime()},
                error: function (xhr, ajaxOptions, thrownError) {
                    if (xhr.status == 500) {
                        alert('Server error');
                    } 
                        this.tryCount++;
                        if (this.tryCount < this.retryLimit) {
                            $.ajax(this);
                            //return;
                        }
                }
           }) ;  

And this is the .done and fail:

request.done(function(msg) 
{
    $(msg).find("Response").each(function()
    {
             // my code here
    });
});

request.fail(function(jqXHR, textStatus, errorThrown) 
{ 
    $("#message").html(errorThrown);    
});

回答1:

The .done() and .fail() methods are part of Deferred Object which is implemented in the jqXHR object returned by $.ajax(). Callbacks which you register with them are not part of $.ajax() options so you can't pass them to another $.ajax(). In your code you are subscribing only to parent $.ajax() Deferred Object callbacks. To achieve the result you want, you should wrap entire operation in another Deferred Object and use .resolveWith()/.rejectWith() methods to pass the proper context. Also you need to remember that Deferred Object can change its state to resolved or rejected only once (in another words if it fails it can't succeed later). So the final code might look like this:

var request = $.Deferred(function(deferred) {
    $.ajax({    
        url: 'wcf.php',
        type: 'POST',
        dataType: 'xml',
        async: false,
        timeout: 5000,
        tryCount: 0,
        retryLimit: 3,
        data: { barcode: value, curPrxID: currentPrxID, timestamp: (new Date).getTime()},
        error: function (xhr, ajaxOptions, thrownError) {
            if (xhr.status == 500) {
                alert('Server error');
            }
            this.tryCount++;
            if (this.tryCount < this.retryLimit) {
                $.ajax(this).done(function(data, textStatus, jqXHR) {
                    deferred.resolveWith(this, [data, textStatus, jqXHR]);
                }).fail(function(jqXHR, textStatus, errorThrown) {
                    if (this.tryCount >= this.retryLimit) {
                        deferred.rejectWith(this, [jqXHR, textStatus, errorThrown]);
                    }
                });
            }
        }
    }).done(function(data, textStatus, jqXHR) {
        deferred.resolveWith(this, [data, textStatus, jqXHR]);
    });
}).promise();

request.done(function(msg) {
    $(msg).find("Response").each(function() {
        //Success code here
    });
});

request.fail(function(jqXHR, textStatus, errorThrown) { 
    $("#message").html(errorThrown);
});