Since jQuery v1.5, it became possible to set timeout on script and JSONP requests. Before that version, timeout was only applied to other types of AJAX requests. Timeout can be very useful as it is the only way to detect the failure of a JSONP request.
When a request timeouts and you need to retry it, here is how to do it using ajaxPrefilter that was introduced in jQuery v1.5. ajaxPrefilter is a callback function that is called before each request is sent to $.ajax() and can be used to handle or modify custom AJAX settings.
In the following snippet, a simple JSONP request is made to get latest tweet from my Twitter timeline.
-
Note that a custom option "retryMax" was set to 2 to retry the request when it timeouts for 2 times maximum.
- You should consider the worst case when setting the timeout (in milliseconds).
$(document).ready( function(){
// sample jsonp request to get latest tweet
$.ajax({
dataType: 'jsonp'
,url: 'https://api.twitter.com/1/statuses/user_timeline.json'
,data: { screen_name: 'mike_more', count: 1 }
,success: function(json) {
// display the tweet text on success
alert( json[0].text );
}
,error: function( jqXHR, textStatus, errorThrown ){
// display error status on failure
alert( 'error: ' + textStatus );
}
,timeout:5000
,retryMax: 2
});
});
Now, let's register a prefilter callback. Code should be placed before doing the previous JSONP call -and of course, after including jQuery script!
// register AJAX prefilter : options, original options
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
// retry not set or less than 2 : retry not requested
if( !originalOptions.retryMax || !originalOptions.retryMax >=2 ) return;
// no timeout was setup
if( !originalOptions.timeout >0 ) return;
if( originalOptions.retryCount ) {
// increment retry count
each time
originalOptions.retryCount++;
}else{
// init the retry count if not set
originalOptions.retryCount = 1;
// copy original error callback on first time
originalOptions._error = originalOptions.error;
};
// overwrite error handler for current request
options.error = function( _jqXHR, _textStatus, _errorThrown ){
// retry max was exhausted or it is not a timeout error
if( originalOptions.retryCount >= originalOptions.retryMax || _textStatus!='timeout' ){
// call original error handler if any
if( originalOptions._error ) originalOptions._error( _jqXHR, _textStatus, _errorThrown );
return;
};
// Call
AJAX again with original options
$.ajax( originalOptions);
};
});
- Function checks that retry max and timeout options were set.
- On the first iteration, it initializes the retry counter and copy the error callback to another option before overriding it.
- On other iterations, it increments the retry counter.
- Overrides the error callback for current request to be able to call the AJAX request again when it timeouts.
Very elegant solution, thank you !
Thanks a lot for this!
It was featured as an answer to my question on SO :)
http://stackoverflow.com/questions/8881614/how-do-i-resend-a-failed-ajax-request