Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

A JavaScript Promise represents an outcome that may be fulfilled or rejected. The Promise constructor’s executor runs immediately, but handlers attached with .then() run later—as microtasks in the browser. This distinction explains why Promise callbacks often appear after synchronous code but before timer callbacks, and why await pauses one async function without blocking the rest of the program.

What happens when you create a Promise?

Calling new Promise(executor) invokes executor immediately, during construction. The executor can start an operation and receives resolve and reject functions. Calling either settles the Promise, unless it has already been settled; resolving with another Promise or thenable instead locks the new Promise to that value’s eventual outcome.

For example, the log inside this executor happens before the next statement:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const promise = new Promise((resolve) => {
  console.log("executor");
  resolve("done");
});

console.log("after construction");

The output begins with executor, then after construction. A Promise does not make synchronous work asynchronous or move it to another thread. It provides a way to represent an outcome and schedule reactions to that outcome. See MDN’s Promise reference.

Why does .then() run later?

Calling .then(onFulfilled, onRejected) registers reactions. Those reactions are not called inline, even if the Promise is already settled. MDN Web Docs puts it this way: “To avoid surprises, functions passed to then() will never be called synchronously, even with an already-resolved promise:”

In the browser’s event-loop model, Promise reactions are microtasks. Once the current JavaScript job finishes, the browser processes queued microtasks before selecting another task, such as a timer callback. This accounts for the order in the following example:

console.log("sync start");

Promise.resolve().then(() => console.log("promise reaction"));
setTimeout(() => console.log("timer task"), 0);

console.log("sync end");

In an ordinary browser case, the output is:

sync start
sync end
promise reaction
timer task

The timer’s 0 does not mean it runs immediately or has a guaranteed wall-clock delay. It schedules a task; the Promise reaction is processed as a microtask before the event loop selects the next task. MDN explains this interaction in Using promises and its JavaScript execution model. Host scheduling details can differ, so this browser explanation should not be assumed to cover every Node.js scheduling case.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does a microtask run in parallel?

No. A microtask is scheduled work, not an independent thread. Each JavaScript job runs to completion on its agent. A long synchronous function can therefore delay user input, timers, and Promise reactions, even if those callbacks are already waiting.

Several asynchronous operations can be in flight at once, and their completion callbacks can interleave. That is concurrency, not a guarantee that JavaScript executes those callbacks simultaneously on the same agent. Promise combinators coordinate outcomes; they do not themselves make operations parallel.

What does await pause?

await suspends the continuation of the async function containing it until the awaited value settles. It does not freeze the program or block the caller. Other synchronous code and pending work can proceed while that function is suspended. Even awaiting an already-fulfilled Promise defers the async function’s continuation.

async function loadValue() {
  console.log("before await");
  const value = await Promise.resolve("ready");
  console.log(value);
}

loadValue();
console.log("caller continues");

before await appears first. The async function then suspends, so caller continues is logged before ready. When the awaited value fulfills, the expression evaluates to that value. If it rejects, the rejection is thrown at the await point and can be handled with ordinary try/catch. See MDN’s await reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do Promise errors propagate?

A rejection is an error path through the chain. A .catch() handler handles a rejection and returns a new Promise; if the handler throws or returns a rejected Promise, the chain remains rejected. With await, put the awaited expression inside try and handle its rejection in catch.

try {
  const result = await fetchData();
  console.log(result);
} catch (error) {
  console.error("The operation failed:", error);
}

Without a rejection handler, the error is not converted into a successful result. Choose where to handle it based on which code can recover or provide useful context.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Which Promise combinator fits the completion rule?

Choose a combinator by asking whether you need every outcome, every successful result, any success, or simply the first outcome. These methods aggregate already-created values or Promises; they do not start work in parallel by themselves.

Method Completes when Rejection behavior
Promise.all() All inputs fulfill Rejects when an input rejects
Promise.allSettled() All inputs settle Fulfills with each input’s outcome
Promise.any() The first input fulfills Rejects if all inputs reject
Promise.race() The first input settles Adopts that first outcome, whether fulfillment or rejection

For example, use allSettled() when a dashboard should report each request’s result even if some fail. Use any() when any successful result is sufficient. Use race() when the first settlement should determine the aggregate result, not just the first success. MDN’s Promise reference documents these methods.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.