DataTables serverSide request cancellation and stale response ordering
0 reputation · 15 Feb 2021, 21:27 UTC
0 reputation · 15 Feb 2021, 21:27 UTC
When serverSide: true is enabled, every search keystroke, column sort, or page change triggers a new Ajax request. DataTables debounces input with searchDelay, but it does not cancel an in-flight request before starting another. Because responses carry no built-in sequence token, a slow earlier response can arrive after a faster later one and overwrite newer rows.
The documented ajax.reload() and ajax.load() methods do not expose the underlying jqXHR object or return a promise, so cancellation must be handled inside a custom ajax function. Object-form ajax settings are forwarded to jQuery, meaning jQuery's timeout option applies, but DataTables itself defines no dedicated request-timeout setting.
Failure behavior is governed by $.fn.dataTable.ext.errMode and the xhr event. An aborted request can surface through the error path unless errMode is set to 'none' or the abort is handled explicitly. The exact event names and searchDelay defaults differ across DataTables 1.10.x, 1.11, and 2.x, so behavior must be confirmed against the reference docs for the running version.
Can a custom ajax function reliably discard out-of-order responses without relying on undocumented internals, and which documented mechanism—if any—lets a developer set a per-request timeout that DataTables honors independently of jQuery's global defaults?
34775 reputation · 16 Feb 2021, 07:47 UTC
Yes. A custom ajax function can reliably discard out-of-order responses using only documented DataTables APIs. There is no DataTables-specific request-timeout setting; the documented mechanism is to pass a timeout value inside the settings object that your ajax function forwards to jQuery.ajax.
When ajax is a function, DataTables invokes it with (data, callback, settings). You can keep a counter outside the function, increment it on every call, and attach it to the outgoing payload. In the success handler, compare the token in the response with the latest token you sent; only call the DataTables callback when the response is current.
let latestRequestId = 0;
$('#example').DataTable({
serverSide: true,
ajax: function (data, callback, settings) {
const requestId = ++latestRequestId;
data.requestId = requestId;
$.ajax({
url: '/api/data',
data: data,
dataType: 'json',
timeout: 5000,
success: function (json) {
if (requestId === latestRequestId) {
callback(json);
}
},
error: function () {
if (requestId === latestRequestId) {
callback({ data: [], recordsTotal: 0, recordsFiltered: 0 });
}
}
});
}
});
This uses only the documented ajax function signature and standard jQuery.ajax options. It does not depend on undocumented internals. Network reordering is handled correctly: a late response with an older token is ignored, while the newest response always carries the highest token and is accepted.
DataTables defines no dedicated timeout option. In the function form above, timeout: 5000 is passed directly to jQuery.ajax, which applies it to that single request and overrides any global $.ajaxSetup timeout for the call. If the request is aborted or times out, jQuery triggers the error path. To prevent DataTables from raising a default alert on that abort, set $.fn.dataTable.ext.errMode = 'none' and observe the xhr event for status 0.
The token and timeout patterns are stable across DataTables 1.10.x, 1.11, and 2.x because they rely on the ajax function contract, not on debounce internals. The searchDelay default differs by version—200 ms in 1.10.x/1.11 and 0 ms in 2.x—so confirm the running version with $.fn.dataTable.version before tuning debounce behavior.
timeout to a small value and confirm the xhr event fires with status 0 while the table remains stable.$.fn.dataTable.version against the documented searchDelay default for that release.If your ajax option is currently a string URL or plain object and cannot be replaced by a function, the client-side token approach is not available without rewriting the entire ajax configuration. Are you able to switch the ajax option to a function, or is it fixed by an existing integration?
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.