Callbacks, Promises and Futures

Choose how a report result reaches its caller

A report-loading operation needs to deliver either the student’s marks or a failure. Calling code should know how to receive that result without guessing whether it already exists.

A callback is a supplied function. A promise represents one eventual fulfilled value or rejection. A future is a related eventual-result abstraction whose precise operations depend on its language or library.

  1. Compare contracts

    Distinguish a callback role from an eventual-result object.

  2. Chain results

    Return values needed by the next promise handler.

  3. Handle failure

    Explain rejection propagation and recovery.

A chain passes returned results to the next stage

  1. Eventual input

    Obtain the marks array.

    [40, 35]
  2. Transformation

    Return the total from then.

    75
  3. Next handler

    Receive the returned total.

    Display 75
Read these stages alongside the complete example. They explain the relationship; they do not execute code.

A promise is a result contract, not a callback count

JavaScript promises begin pending unless already settled. Settlement chooses fulfillment or rejection once. then returns a new promise that follows the callback’s returned value, returned promise or thrown error.

A callback may be called once, never or repeatedly according to its API. For example, a button handler can run for many clicks. An error-first Node.js callback convention uses an error argument and result argument, but not every callback API follows that convention.

Before starting, review callback timing. These examples use JavaScript; other languages can use different syntax and rules.

Return a total through a promise chain

The first handler receives marks and returns 75. The next handler receives that returned number and prints it. The synchronous Waiting message prints before either handler.

No network request occurs: Promise.resolve supplies local marks so we can verify the chain independently of a service.

JavaScript · local teaching example

Promise.resolve([40, 35])
  .then(marks => marks[0] + marks[1])
  .then(total => console.log(total));
console.log("Waiting");

Expected output

Waiting
75

A thrown validation error becomes a rejection

The handler rejects invalid marks by throwing. The following success handler is skipped, and catch receives the error. Returning from catch would recover the chain with that returned value.

This error belongs to the promise chain. A try/catch wrapped only around registering the handler would not catch a later thrown error inside it.

JavaScript · local teaching example

Promise.resolve(-1)
  .then(mark => {
    if (mark < 0) throw new Error("Invalid mark");
    return mark;
  })
  .then(mark => console.log("Saved " + mark))
  .catch(error => console.log(error.message));

Expected output

Invalid mark

Apply the rule to a small change

Return an uppercase student name from one handler and prefix it in the next handler.

Worked answer

The first handler returns MAYA. The second receives that string and displays Student: MAYA. Omitting the first return would pass undefined instead.

JavaScript · local teaching example

Promise.resolve("Maya")
  .then(name => name.toUpperCase())
  .then(name => console.log("Student: " + name));

Expected output

Student: MAYA

Recognize mistakes and limits

Return asynchronous work from a handler when later steps must wait for it. Starting a promise inside then without returning it breaks the intended chain and can leave failure unhandled.

A promise is not an automatic cancellation mechanism, a separate thread or proof of success. Cancellation depends on the underlying operation and its API.

Future is not a universal interchangeable name with identical methods. Python concurrent.futures.Future, for example, exposes result and exception behavior that differs from JavaScript then. Learn the concrete API rather than copying syntax between languages.

For the language or tool rules used here, see JavaScript promise chaining and timing.

Check the core idea

What reaches the next then when a block handler has no return?
Choose one answer. You can try again.

Answer and explanation

undefined, assuming the handler completes normally.

Correct. A normal function without an explicit returned value returns undefined.

Apply the idea to a new situation

JavaScript · code for this question

Promise.resolve(-1)
  .then(mark => {
    if (mark < 0) throw new Error("Invalid mark");
    return mark;
  })
  .then(mark => console.log("Saved " + mark))
  .catch(error => console.log(error.message));
What happens to the thrown Invalid mark error in the shown chain?
Choose one answer. You can try again.

Answer and explanation

The later catch receives the rejection reason.

Correct. This chain supplies a failure handler.

Make the completion and failure contract explicit

Callbacks supply callable behavior; promises represent a one-time eventual outcome and support chaining. Return the next result or operation and handle rejection in the chain that owns it.

Connect this idea with awaiting promise results and synchronous and awaited failures.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Async and Await →