The then() method registers success and optional failure handlers while building a transformable promise chain. This tutorial covers syntax, five examples, comparisons with done(), fail(), and deprecated pipe(), and jQuery 3+ chaining rules.
01
Syntax
then(ok, err)
02
Returns
New promise
03
Transform
Return values
04
Chain
Sequential steps
05
vs done
Side vs pipe
06
jQuery 3+
Promises/A+
Fundamentals
Introduction
Real apps rarely stop at one async step. You fetch a user ID, then load a profile, then format the result. The then() method is jQuery’s primary tool for linking those steps — handling both success and failure in one call and passing transformed values forward.
Since jQuery 3.0, then() follows Promises/A+ semantics and replaces deprecated pipe(). It works on Deferreds, promises returned from promise(), and jqXHR objects from $.ajax().
Concept
Understanding the then() Method
then(onFulfilled, onRejected) registers callbacks that run when the promise settles. Unlike done() and fail(), what you return from a then() handler matters — that return value (or returned promise) becomes the input for the next link in the chain.
Each then() call returns a new promise, so you can keep chaining without mutating the original Deferred.
💡
Beginner Tip
Use done() for simple “log the result” side effects. Use then() when the next step needs the transformed return value — that is the difference between listening and piping data through a pipeline.
Foundation
📝 Syntax
General form of deferred.then:
jQuery
deferred.then( onFulfilled [, onRejected ] )
Parameters
onFulfilled — runs when the promise resolves; may return a value or another promise for the chain to wait on.
onRejected (optional) — runs when the promise rejects; can recover by returning a value or let errors propagate downstream.
Return value
Returns a new promise representing the outcome of the handlers and any chained async work.
Pass null as the first argument to skip the success handler. Returning a normal value from onRejected converts the chain back to fulfilled — similar to catch() recovery.
Example 5 — then() vs done()
Same starting value — only then() passes a transformed result forward.
Use done() when you only need to react. Use then() when the return value must flow to the next step — the core reason both APIs exist.
Applications
🚀 Use Cases
Chained AJAX — load a resource, transform the response, then fetch related data.
Data pipelines — parse JSON, validate, enrich, and render through sequential then() steps.
Unified error handling — attach onRejected or trailing catch() for a whole chain.
Migrating from pipe() — replace deprecated filters with then(onFulfilled, onRejected).
Parallel tasks — combine multiple promises with $.when(), then process results in one then().
🧠 How a then() Chain Propagates Values
1
Settle
Parent promise resolves or rejects with initial value(s).
Input
2
then()
Matching handler runs; its return value (or promise) becomes the next input.
Transform
3
New promise
Each then() returns a fresh promise for the following link.
Chain
=
🔗
Pipeline complete
Final then() or done() receives the last transformed value.
Important
📝 Notes
Since jQuery 3.0, then() is Promises/A+ compatible — prefer it over pipe().
Returning nothing (undefined) passes undefined to the next handler.
Thrown errors inside then() reject the returned promise automatically.
then() handlers on an already-settled promise may run asynchronously (microtask) in jQuery 3+.
For simple logging after AJAX, .done() / .fail() remain readable — use then() when transforming.
Compatibility
Browser Support
deferred.then() has been available since jQuery 1.5. Promises/A+ semantics apply in jQuery 3.0+.
✓ jQuery 1.5+
jQuery Deferred.then()
Supported in jQuery 1.5+, 2.x, and 3.x. Use jQuery 3+ for modern chaining that aligns with native Promise.then().
100%With jQuery loaded
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
deferred.then()Universal
Bottom line: Core chaining API for jQuery Deferreds. In new code, prefer then() over deprecated pipe().
Wrap Up
🎉 Conclusion
The deferred.then() method is how you build async pipelines in jQuery — handling success and failure while passing transformed values from step to step. It is the modern replacement for pipe() and the transform-aware counterpart to done() and fail().
You have now covered the core Deferred API. Explore the broader jQuery docs or revisit the catch() and always() handlers for complementary chain patterns.
Keep chains flat — extract named functions for long pipelines
Migrate pipe() calls to then() in jQuery 3+
❌ Don’t
Nest many anonymous then() callbacks (pyramid of doom)
Use done() when you need to transform values
Start new pipe() chains in modern code
Forget to return inside then() when the next step needs data
Mix untested jQuery 2 and 3 chaining semantics in one codebase
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about then()
How to chain and transform async results in jQuery.
5
Core concepts
📝01
Syntax
ok + err
API
🔗02
Returns
New promise
Chain
⇄03
Transform
Return value
Pipe
vs04
done()
Listen only
Compare
3+05
Modern
Not pipe()
Migrate
❓ Frequently Asked Questions
then(onFulfilled, onRejected) registers handlers for success and optional failure. In jQuery 3+, it follows Promises/A+ semantics: the fulfilled handler's return value becomes the input for the next link in the chain, and then() returns a new promise.
done() and fail() only register side-effect callbacks — their return values are ignored. then() transforms the chain: returning a value or promise from onFulfilled/onRejected affects downstream steps. then() also returns a new promise for chaining.
Yes. pipe() is deprecated since jQuery 3.0. Use then(onFulfilled, onRejected) for the same transform-and-chain behavior with modern promise semantics.
A plain value (passed to the next then), another Deferred or promise (chain waits for it), or throw / return a rejected promise to fail the chain.
Yes. Each then() returns a new promise, so you can write dfd.then(step1).then(step2).then(step3) for sequential async pipelines.
Since jQuery 3.0, Deferred promises are Promises/A+ compatible — then() chaining, return propagation, and error bubbling behave similarly to native Promises, with jQuery-specific extras like progress() still available on Deferreds.
Did you know?
jQuery 3.0 rewrote Deferreds to be interoperable with native ES6 Promises — you can pass a jQuery promise into Promise.resolve() and mix it with async/await in modern browsers, as long as you account for jQuery’s extra methods like done() that native Promises do not have.