AJAX helpers and why modern code moves on
The ajax family, its Deferred objects, and an honest comparison with fetch and the native APIs that replaced the rest of jQuery.
The ajax family
// the general form
$.ajax({
url: '/api/items',
method: 'GET',
data: { page: 2, tag: 'css' }, // serialised to the query string
dataType: 'json', // parses the response for you
headers: { 'X-CSRF-Token': token },
timeout: 8000
}).done(function (items) {
render(items);
}).fail(function (xhr, status, error) {
console.error(status, xhr.status);
}).always(function () {
hideSpinner();
});
// shortcuts
$.get('/api/items', { page: 2 }, render);
$.post('/api/items', { name: 'new' }, render);
$.getJSON('/api/items.json').done(render);
$('#form').serialize(); // query-string from all fields
$('#form').serializeArray(); // [{ name, value }, ...]| Option | Meaning |
|---|---|
dataType | json, html, text, xml — how the body is parsed before your callback |
contentType | Request header; set application/json and stringify the body yourself |
cache: false | Appends a timestamp to GET requests — hides caching bugs rather than fixing them |
beforeSend | Runs before the request leaves; the classic place for a CSRF header |
global: false | Suppresses the document-wide ajaxStart / ajaxError events |
statusCode | Per-status callbacks, for example { 404: onMissing } |
done, fail and Deferreds
const req = $.getJSON('/api/items');
req.done(onOk).fail(onErr).always(cleanup);
// then() returns a new promise, so results can be transformed
req.then(function (items) {
return $.getJSON('/api/items/' + items[0].id);
}).done(function (first) {
console.log(first);
});
// wait for several requests
$.when($.getJSON('/a'), $.getJSON('/b'))
.done(function (a, b) {
render(a[0], b[0]); // each argument is [data, statusText, xhr]
});- A jQuery Deferred is promise-like: it has
done,fail,thenandalways, but it is not a nativePromiseinstance. - You cannot
awaita jQuery Deferred directly and expect a rejection to throw. Wrap it:await new Promise((res, rej) => req.done(res).fail(rej)). $.when()resolves with one argument per request, each wrapped in an array — a frequent source of confusion.- jQuery 3 fixed the long-standing Deferred bug where exceptions inside
thenwere swallowed, so behaviour now matches the Promises/A+ spec closely.
Why modern projects skip jQuery
| jQuery solved | Native replacement available since |
|---|---|
$(selector) | querySelector / querySelectorAll |
addClass / toggleClass | classList |
.on() delegation | addEventListener with closest() |
$.ajax | fetch, then axios or ky for niceties |
animate() | CSS transitions and the Web Animations API |
$.each | Array.prototype.forEach / for...of |
$.when | Promise.all / Promise.allSettled |
$.extend | Object.assign / spread |
// jQuery version
$('.remove').on('click', function () {
$(this).closest('li').addClass('gone');
});
// native equivalent, about the same length today
document.addEventListener('click', (e) => {
const btn = e.target.closest('.remove');
if (!btn) return;
btn.closest('li').classList.add('gone');
});- Bundle cost: gzipped jQuery is roughly 30 KB before your own code — meaningful for a page that only needs a class toggle.
- jQuery's plugins are its real moat: date pickers, validators, data tables and legacy vendor widgets still assume it is present.
- Legacy browser support was the original reason to use it; that reason is gone now that evergreen browsers are the baseline.
- Mixed codebases are the worst outcome — pick one style per feature and keep the two worlds from re-rendering the same DOM.
💡
The honest rule: jQuery is still a reasonable choice when you maintain existing jQuery code or depend on jQuery plugins, and a poor choice for a new page that only needs a dozen lines of native DOM work.
FAQ
Can I migrate from $.ajax to fetch without rewriting everything?
Yes. Wrap
fetch in a helper that returns JSON, throws on non-OK statuses and handles timeouts, then replace the $.ajax calls one route at a time. The call sites shrink because the helper carries the common options.Is jQuery still maintained?
Yes — the 3.x line still receives releases and security fixes, and the 4.x branch modernises internals. Maintenance is not abandonment, but new browser platforms have made most of its original job unnecessary.
Related
Events, effects and attributes Requests with fetch
Last refreshed 2026-09-18.