jQuery Deferred progress() Method

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Progress handlers

What You’ll Learn

The progress() method registers callbacks that run when notify() sends interim updates. Use it for progress bars, step labels, and status text while a Deferred is still pending — then handle the final result with done() or fail().

01

Syntax

dfd.progress(fn)

02

notify()

Triggers handlers

03

Pending

Not final state

04

Multiple

Many handlers OK

05

vs done()

Updates vs finish

06

Since 1.7

With notify API

Introduction

Success and failure callbacks tell users how a task ended — but long operations also need mid-flight feedback. jQuery’s progress() method listens for notify() pings: percentage complete, current step, or any status message emitted while the Deferred remains pending.

Think of the trio as a complete async story: progress() for updates, done() for success, fail() for errors.

Understanding the progress() Method

progress() is part of jQuery’s Deferred Object API (since jQuery 1.7). Calling deferred.progress(callback) adds your function to a progress queue. Each time the Deferred owner calls notify() or notifyWith(), jQuery invokes every progress handler with the notify arguments.

Progress handlers do not change Deferred state. The operation stays pending until resolve() or reject() runs — only then do done() or fail() fire.

💡
Beginner Tip

Register progress() before the first notify(), just like attaching done() before resolve(). The reference example does this correctly — our examples also call resolve() at the end so done() confirms completion.

📝 Syntax

General form of deferred.progress:

jQuery
deferred.progress( progressCallback [, progressCallback ] )

Parameters

  • progressCallback — function executed on each notify() call. Receives whatever arguments were passed to notify() or notifyWith().

Return value

  • Returns the same Deferred object for chaining done(), fail(), or another progress().

Full progress + completion flow

jQuery
const dfd = $.Deferred();

dfd.progress(function (message) {
  console.log("Progress:", message);
});

dfd.done(function (result) {
  console.log("Done:", result);
});

dfd.notify("50% complete");
dfd.notify("90% complete");
dfd.resolve("Operation completed successfully");

⚡ Quick Reference

GoalCode
Listen for progressdfd.progress(fn)
Emit progress (owner)dfd.notify(value)
Success handlerdfd.done(fn)
Error handlerdfd.fail(fn)
Progress with custom thisdfd.notifyWith(ctx, [value])

📋 progress() vs done() vs notify()

Three related methods — listener, finisher, and emitter.

progress()
listen

Register update handler

notify()
emit

Send update (owner)

done()
on success

Final resolve

Frequency
many times

While pending

Examples Gallery

Each example shows how progress() receives notify() updates. Use the Try-it links to run them interactively.

📚 Getting Started

Log progress messages, then resolve when work finishes.

Example 1 — Status Message Updates

Register progress(), receive two notify() calls, then resolve().

jQuery
const dfd = $.Deferred();

dfd.progress(function (message) {
  console.log("Progress:", message);
});

dfd.done(function (result) {
  console.log("Done:", result);
});

dfd.notify("50% complete");
dfd.notify("90% complete");
dfd.resolve("Operation completed successfully");
Try It Yourself

How It Works

Each notify() triggers all progress handlers. resolve() settles the Deferred and runs done() — progress and completion are separate phases.

Example 2 — Drive a Progress Bar

Use numeric percentages from notify() to update a bar width.

jQuery
const dfd = $.Deferred();

dfd.progress(function (percent) {
  $("#upload-bar").css("width", percent + "%");
  console.log("Upload:", percent + "%");
});

dfd.done(function () {
  console.log("Upload finished");
});

[25, 50, 75, 100].forEach(function (pct) {
  dfd.notify(pct);
});

dfd.resolve({ file: "photo.jpg" });
Try It Yourself

How It Works

progress() is ideal for UI feedback. Keep final rendering or navigation in done() after the last notify and resolve.

📈 Practical Patterns

Multiple listeners, full handler trio, and delayed notify calls.

Example 3 — Multiple progress() Handlers

Split progress work — logging and UI — across separate callbacks.

jQuery
const dfd = $.Deferred();

dfd.progress(function (step) {
  console.log("Log step:", step);
});

dfd.progress(function (step) {
  $("#status").text("Step " + step + " of 3");
});

dfd.notify(1);
dfd.notify(2);
dfd.notify(3);
dfd.resolve("All steps done");
Try It Yourself

How It Works

Every progress handler runs on each notify — same queuing behavior as multiple done() handlers on resolve.

Example 4 — progress(), done(), and fail()

Register all three paths — progress updates, success, and failure stay separate.

jQuery
function runTask(shouldFail) {
  const dfd = $.Deferred();

  dfd.progress(function (pct) {
    console.log("Working:", pct + "%");
  });

  dfd.done(function (msg) {
    console.log("Success:", msg);
  });

  dfd.fail(function (err) {
    console.log("Failed:", err);
  });

  dfd.notify(50);

  if (shouldFail) {
    dfd.reject("Validation error");
  } else {
    dfd.notify(100);
    dfd.resolve("Saved");
  }

  return dfd;
}
Try It Yourself

How It Works

Progress can fire before either outcome. After reject(), no further progress or done handlers run — only fail().

Example 5 — Timed Progress (Reference Pattern)

Matches the reference’s delayed notify() calls with explicit resolve() at the end.

jQuery
const dfd = $.Deferred();

dfd.progress(function (message) {
  console.log("Progress:", message);
});

dfd.done(function (result) {
  console.log("Done:", result);
});

setTimeout(function () {
  dfd.notify("50% complete");
}, 400);

setTimeout(function () {
  dfd.notify("90% complete");
}, 900);

setTimeout(function () {
  dfd.resolve("Operation completed successfully");
}, 1400);
Try It Yourself

How It Works

Register handlers first, then emit progress as async milestones arrive. The final timer calls resolve() so users see both interim updates and completion.

🚀 Use Cases

  • File uploads — update a progress bar as bytes are sent.
  • Multi-step wizards — show “Step 2 of 5” as each stage completes.
  • Data imports — log row counts or batch numbers during processing.
  • Long computations — report iteration progress without blocking the UI thread.
  • Loading indicators — swap spinner text from “Loading…” to specific status messages.

🧠 How progress() Fits the Deferred Lifecycle

1

Register

dfd.progress(fn) queues handlers while state is pending.

Listen
2

Notify

Owner calls notify() — every progress handler runs.

Update
3

Settle

resolve() or reject()done() or fail() runs.

Finish
=

Informed user

Progress during work, final message via done() or fail().

📝 Notes

  • progress() only runs when notify() or notifyWith() is called — it does not fire on resolve or reject alone.
  • Register handlers before the first notify for predictable behavior.
  • Put final success logic in done(), not progress().
  • Consumers with only a promise() view can attach progress() but cannot call notify().
  • Native Promises have no progress() — this is jQuery-specific.

Browser Support

deferred.progress() has been available since jQuery 1.7 alongside notify(). It works wherever jQuery Deferred runs.

jQuery 1.7+

jQuery Deferred.progress()

Supported in jQuery 1.7+, 2.x, and 3.x. Progress listeners are a jQuery extension — not part of the native Promise standard.

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

Bottom line: Pair progress() with notify() for jQuery long-running tasks. For non-jQuery apps, use events or other progress patterns.

🎉 Conclusion

The deferred.progress() method listens for interim updates on jQuery Deferreds. Register handlers early, pair them with notify() from the task owner, and finish with done() or fail() for the final outcome.

Next, explore promise() to expose a read-only view of a Deferred, or review notify() for the emitter side of progress.

💡 Best Practices

✅ Do

  • Register progress() before the first notify()
  • Use clear, user-friendly progress messages
  • Pair with done() and fail() for outcomes
  • Throttle very frequent updates if needed
  • Update UI in progress; commit state in done

❌ Don’t

  • Treat progress as final success — use done()
  • Call notify() after resolve or reject
  • Spam hundreds of updates per second
  • Assume native Promises support progress()
  • Skip error handlers on long-running tasks

Key Takeaways

Knowledge Unlocked

Five things to remember about progress()

How to listen for jQuery Deferred progress updates.

5
Core concepts
📢 02

notify()

Triggers fn

Pair
03

Pending

Interim only

State
📈 04

Many calls

Per notify

Repeat
done 05

Then done

Final result

Finish

❓ Frequently Asked Questions

progress() registers a callback that runs whenever notify() or notifyWith() sends a progress update. The Deferred stays pending until resolve() or reject() — progress handlers report interim status, not final outcome.
done() runs once when the Deferred resolves successfully. progress() can run many times while work is still in progress. done() handles the finish line; progress() handles updates along the way.
Calls to notify() and notifyWith() on the same Deferred. Each notify fires every registered progress callback with the arguments passed to notify.
Yes. jQuery queues them and invokes each one on every notify(), similar to multiple done() handlers on resolve.
No new progress events fire after settlement. Register progress() before notify() calls, and send all progress updates before resolve() or reject().
No. progress() is a jQuery Deferred extension paired with notify(). Native Promises only support fulfillment and rejection — use events, callbacks, or Observables elsewhere for progress.
Did you know?

jQuery’s progress API was inspired by the need for upload indicators before modern fetch and native Promises existed. The listener (progress) and emitter (notify) split keeps consumers from accidentally settling someone else’s Deferred.

Continue to promise()

Learn how to hand consumers a read-only view of a Deferred.

promise() tutorial →

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