jQuery AJAX Complete Callback Explained
The jQuery AJAX complete callback is a predefined
function that executes immediately after an HTTP request finishes,
regardless of whether that request resulted in a success or an error. It
serves as an essential mechanism for running cleanup tasks, updating
user interface states, and resetting flags. By understanding how and
when the complete function fires, developers can ensure
that their web applications maintain a predictable and responsive state
after asynchronous communication.
Execution Timing and Parameters
In the standard jQuery AJAX lifecycle, the request proceeds through several stages:
beforeSend: Fires before the request is dispatched.successorerror: Fires depending on whether the server returned a successful HTTP status code (2xx) or an error code (4xx, 5xx), or if the request timed out.complete: Fires last, aftersuccessorerrorhas finished executing.
The complete callback accepts two arguments:
jqXHR: The jQuery XMLHttpRequest object containing details about the response, including response headers, status codes, and response text.textStatus: A string indicating the status of the request. Common values include"success","notmodified","nocontent","error","timeout","abort", or"parsererror".
Primary Use Cases
1. Hiding Loading Spinners
When an asynchronous operation starts, applications typically display
a loading indicator. Because network requests can fail or succeed,
hiding the spinner inside both success and
error duplicates logic. Placing the hide operation inside
complete guarantees that the spinner disappears as soon as
the request ends, preventing the UI from getting stuck in a loading
state.
2. Re-enabling Form Controls
To prevent duplicate submissions, submit buttons are often disabled
when a user initiates a request. The complete callback is
the ideal location to re-enable these controls, ensuring users can
attempt submission again if an error occurs or proceed after a
successful transaction.
3. State Cleanup and Polling
If an application polls a server at fixed intervals, the next poll
cycle should often wait until the current one finishes. Triggering the
next request inside the complete callback prevents
overlapping requests from building up over slow network connections.
Code Example
$.ajax({
url: "https://api.example.com/data",
type: "GET",
beforeSend: function() {
$("#submit-btn").prop("disabled", true);
$("#loading-spinner").show();
},
success: function(response) {
$("#content").html(response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.error("Request failed: " + textStatus);
},
complete: function(jqXHR, textStatus) {
// Runs regardless of success or error
$("#loading-spinner").hide();
$("#submit-btn").prop("disabled", false);
}
});complete
Callback vs. .always() Promise Method
In modern jQuery implementations (version 1.5 and above), the
jqXHR object implements the Promise interface. While the
complete setting inside the $.ajax()
configuration remains fully supported, jQuery also provides the
.always() method, which performs the exact same role using
promise chaining:
$.ajax({
url: "https://api.example.com/data",
type: "GET"
})
.done(function(data) {
// Equivalent to success
})
.fail(function(jqXHR, textStatus) {
// Equivalent to error
})
.always(function() {
// Equivalent to complete
$("#loading-spinner").hide();
});Both approaches guarantee post-request execution, allowing you to centralize teardown logic without duplicating code across success and failure handlers.