DataTables displays stale data due to out‑of‑order Ajax responses
0 reputation · 18 Jul 2023, 21:20 UTC
0 reputation · 18 Jul 2023, 21:20 UTC
Goal: Ensure that a DataTables instance in server‑side mode displays only the data from the most recent Ajax request, preventing stale data from appearing when earlier requests finish after later ones.
Constraints: DataTables does not automatically abort previous Ajax requests when a new draw is triggered, so overlapping requests can race; developers must keep a reference to the prior jqXHR and call .abort() themselves, which is not a documented built‑in feature. Timeout handling depends on the global jQuery Ajax timeout setting (via jQuery.ajaxSetup or jqXHR.timeout), affecting all Ajax calls on the page. Furthermore, DataTables relies on the draw parameter to order responses, but if the server ignores or mismatches draw values there is no automatic detection or error, allowing out‑of‑order responses to update the table silently.
Questions: How can developers reliably cancel prior Ajax requests without introducing server‑side side effects? Is there a way to configure DataTables to discard responses with stale or mismatched draw values? Should DataTables provide an instance‑scoped timeout option instead of relying on global jQuery settings?
To ensure DataTables displays only the most recent server-side response:
ajax option (or captured in the preXhr event) and calling .abort() on it.draw parameter exactly as received; DataTables (current versions) automatically discards responses whose draw value does not match the expected draw counter.timeout inside the ajax configuration object (e.g., ajax: { url: '/data', timeout: 30000 }) instead of relying on global jQuery.ajaxSetup.DataTables sends an incrementing integer draw with every server-side request. In modern versions (1.10.x and 2.x), the client-side library compares the draw value returned in the JSON response against the draw it expects for that table instance. If they differ, the response is ignored and the table does not update. This protection only works when the server reads the incoming draw and writes it back unchanged.
DataTables does not automatically cancel in-flight requests when a new draw is triggered (e.g., rapid paging, search keystrokes). Developers must keep a reference to the last jqXHR and abort it:
let lastXhr = null;
$('#example').DataTable({
serverSide: true,
ajax: function (data, callback, settings) {
if (lastXhr) { lastXhr.abort(); }
lastXhr = $.ajax({
url: '/api/data',
data: data,
dataType: 'json',
timeout: 30000, // per-instance timeout
success: callback,
error: function (jqXHR, textStatus) {
if (textStatus !== 'abort') { /* handle real errors */ }
}
});
}
});The error handler must ignore textStatus === 'abort' to avoid spurious error UI.
Passing timeout inside the ajax object (or the $.ajax call in a custom function) scopes the timeout to that table only. Global jQuery.ajaxSetup({ timeout: ... }) affects every Ajax call on the page and should be avoided unless intentionally shared.
If you cannot modify the server to echo draw, implement a local guard in a custom ajax function:
let currentDraw = 0;
ajax: function (data, callback, settings) {
const thisDraw = ++currentDraw;
$.ajax({
url: '/api/data',
data: data,
success: function (resp) {
if (resp.draw === thisDraw) { callback(resp); } // ignore stale
}
});
}draw query parameter (integer) and return it verbatim in the JSON response.sleep(5)) for an early draw and verify the table does not update when that delayed response finally arrives.draw value sent and echoed back to confirm the server returns the identical integer.ajax: { timeout: 5000 } on one table, hit a slow endpoint, and verify only that table's requests time out while other page Ajax calls remain unaffected.The exact behavior of draw-mismatch rejection and event names (preXhr vs xhr) varies between DataTables 1.10.x and 2.x. Please confirm which major version you are using so the recommended event hooks and abort pattern can be precise.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.