jQuery Deferred then() Method

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Chain & transform

What You’ll Learn

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+

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().

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.

📝 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.

Success + failure handlers

jQuery
function loadData() {
  const dfd = $.Deferred();
  setTimeout(function () { dfd.resolve({ items: 3 }); }, 400);
  return dfd.promise();
}

loadData().then(
  function (data) {
    console.log("Success:", data.items, "items");
  },
  function (err) {
    console.error("Failed:", err);
  }
);

⚡ Quick Reference

GoalCode
Handle successdfd.then(fn)
Success + failuredfd.then(ok, err)
Transform and continuedfd.then(x => x * 2).then(...)
Side effect onlydfd.done(fn) (no transform)
Legacy transform (avoid)dfd.pipe(fn) → use then()

📋 then() vs done() / fail() vs pipe()

Three patterns — transform chains, side-effect listeners, and deprecated pipe.

then()
transform + chain

Modern (jQ 3+)

done() / fail()
listen only

Side effects

pipe()
deprecated

Use then()

Returns
new promise

then() only

Examples Gallery

Each example shows a common then() pattern with runnable Deferred code — no fake URLs required. Use the Try-it links to experiment interactively.

📚 Getting Started

Register both fulfilled and rejected handlers on one promise.

Example 1 — Success and Failure Handlers

Pass two callbacks — the second runs only if the promise rejects.

jQuery
function request(ok) {
  const dfd = $.Deferred();
  setTimeout(function () {
    if (ok) {
      dfd.resolve({ message: "Data received" });
    } else {
      dfd.reject("Request failed");
    }
  }, 400);
  return dfd.promise();
}

request(true).then(
  function (data) {
    console.log("OK:", data.message);
  },
  function (err) {
    console.error("ERR:", err);
  }
);
Try It Yourself

How It Works

This mirrors the reference AJAX pattern but uses a simulated request you can run locally. Only one of the two callbacks executes per settlement.

Example 2 — Transform a Value in the Chain

Return a new value from then() — the next step receives it.

jQuery
const dfd = $.Deferred();
dfd.resolve(5);

dfd.then(function (n) {
  return n * 10;
}).then(function (doubled) {
  console.log(doubled);  // 50
});
Try It Yourself

How It Works

Returning 50 from the first then() feeds the second handler — something done() cannot do because it ignores return values.

📈 Practical Patterns

Sequential tasks, error propagation, and when to prefer done().

Example 3 — Sequential Async Tasks

Chain two simulated fetches — the second waits for the first to resolve.

jQuery
function fetchUserId() {
  const d = $.Deferred();
  setTimeout(function () { d.resolve({ id: 42 }); }, 300);
  return d.promise();
}

function fetchProfile(userId) {
  const d = $.Deferred();
  setTimeout(function () {
    d.resolve({ userId: userId, name: "Alex" });
  }, 300);
  return d.promise();
}

fetchUserId()
  .then(function (data) {
    return fetchProfile(data.id);
  })
  .then(function (profile) {
    console.log(profile.name);  // Alex
  });
Try It Yourself

How It Works

Returning a promise from then() pauses the chain until it settles — the standard pattern for chained AJAX or multi-step workflows.

Example 4 — Error Recovery in onRejected

Map a rejection to a fallback value so the chain can continue.

jQuery
const dfd = $.Deferred();
dfd.reject("Network timeout");

dfd.then(null, function (reason) {
  return "Recovered: " + reason;
}).then(function (message) {
  console.log(message);
});
Try It Yourself

How It Works

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.

jQuery
const dfdA = $.Deferred().resolve(3);
const dfdB = $.Deferred().resolve(3);

dfdA.done(function (n) {
  return n + 7;  // return ignored
}).done(function (n) {
  console.log("done chain:", n);  // 3
});

dfdB.then(function (n) {
  return n + 7;
}).then(function (n) {
  console.log("then chain:", n);  // 10
});
Try It Yourself

How It Works

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.

🚀 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.

📝 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.

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 Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari All versions · macOS & iOS
Full support
Microsoft Edge All versions · Chromium & Legacy
Full support
Internet Explorer IE 6+ · Legacy environments
Full support
Opera All modern versions
Full support
deferred.then() Universal

Bottom line: Core chaining API for jQuery Deferreds. In new code, prefer then() over deprecated pipe().

🎉 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.

💡 Best Practices

✅ Do

  • Use then() when return values feed the next step
  • Return promises from handlers for async sub-steps
  • Handle errors with onRejected or trailing catch()
  • 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

Key Takeaways

Knowledge Unlocked

Five things to remember about then()

How to chain and transform async results in jQuery.

5
Core concepts
🔗 02

Returns

New promise

Chain
03

Transform

Return value

Pipe
vs 04

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.

Explore jQuery

Continue with the main jQuery introduction and other tutorials.

jQuery introduction →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful