Deferred, Promises & $.when
Coordinate asynchronous work with jQuery's Deferred objects and $.when.
Long before async/await, jQuery gave us a way to represent “a value that isn't ready yet”: the Deferred. A Deferred is a producer — you resolve() or reject() it. Its promise is the read-only consumer side that others attach .then() callbacks to.
Making your own Deferred
function wait(ms) {
var d = $.Deferred();
setTimeout(function () { d.resolve("done after " + ms + "ms"); }, ms);
return d.promise();
}
wait(500).then(function (msg) {
console.log(msg);
});$.when — wait for several things at once
Every $.ajax() call already returns a promise, so you rarely build Deferreds by hand. Where they shine is combining asynchronous work. $.when resolves once all of its arguments have resolved:
$.when(
$.getJSON("/user.json"),
$.getJSON("/settings.json")
).done(function (userResult, settingsResult) {
// each argument is [ data, statusText, jqXHR ]
console.log(userResult[0], settingsResult[0]);
}).fail(function () {
console.log("at least one request failed");
});jQuery 3 realigned Deferreds to be Promises/A+ compliant. In modern code you can hand a jQuery promise straight toawait—await $.getJSON(url)just works.
Example
When to use it
- A dashboard waits for three parallel API calls to finish before rendering the combined report, using $.when().
- A wizard step validates a field asynchronously via AJAX and returns a Deferred so the next-step logic can await the result.
- A media player pre-loads audio and metadata in parallel and chains $.when() to start playback only when both are ready.
More examples
Wait for two parallel $.ajax calls
$.when() accepts multiple jqXHR Deferreds and calls .done() only when ALL of them have resolved.
<button id="load">Load dashboard</button>
<p id="out"></p>
<script>
$(function () {
$("#load").click(function () {
var reqA = $.get("/api/stats");
var reqB = $.get("/api/alerts");
$.when(reqA, reqB).done(function (resA, resB) {
var stats = resA[0];
var alerts = resB[0];
$("#out").text("Stats: " + stats.count + " Alerts: " + alerts.count);
});
});
});
</script>Create and resolve a custom Deferred
$.Deferred() creates a manual promise; .resolve() triggers .done() and .reject() triggers .fail() consumers.
<button id="run">Run async task</button>
<p id="status"></p>
<script>
function asyncValidate(value) {
var dfd = $.Deferred();
setTimeout(function () {
if (value.length >= 3) dfd.resolve("Valid: " + value);
else dfd.reject("Too short");
}, 500);
return dfd.promise();
}
$(function () {
$("#run").click(function () {
asyncValidate("Alice")
.done(function (msg) { $("#status").text(msg); })
.fail(function (err) { $("#status").text("Error: " + err); });
});
});
</script>Chain Deferreds with .then()
Returning a new Deferred from .then() chains dependent requests sequentially without deeply nesting callbacks.
<button id="chain">Run chain</button>
<p id="log"></p>
<script>
$(function () {
$("#chain").click(function () {
$.get("/api/user/1")
.then(function (user) {
return $.get("/api/orders?userId=" + user.id);
})
.then(function (orders) {
$("#log").text("Orders: " + orders.length);
})
.fail(function () {
$("#log").text("Request failed.");
});
});
});
</script>
Discussion