Web Development · Foundations
Async Programming
On this page 9 sections
In 30 seconds
Asynchronous JavaScript starts an operation and lets the surrounding program continue instead of waiting for every result immediately. A Promise An object representing the eventual completion or failure of an asynchronous operation and its resulting value. Full entry → represents the operation's eventual outcome. You can use .then() and .catch() to handle fulfillment and rejection, or write an async function and use await inside it. await pauses that async function A function whose call returns a Promise and whose body can use await. Full entry → at one point; it does not turn the whole program into a stop sign.
Why this matters
Web programs often need to coordinate work whose result is not available right away. Promises give that later result—and a possible failure—a defined path through the program. Learning the model helps a student read JavaScript without assuming that the next line always receives a finished value. It also builds habits that matter beyond a browser: return promises deliberately, handle failures near the operation that can explain them, and avoid making independent work wait needlessly.
The college version
Promises describe a result that is not ready yet
A Promise is a JavaScript object representing the eventual completion or failure of an asynchronous operation and its resulting value. It has an initial pending The initial promise state before it has fulfilled or rejected. Full entry → state. A pending promise has not yet produced a final outcome. It later becomes fulfilled The state of a promise that completed successfully with a value. Full entry →, carrying a fulfillment value, or rejected The state of a promise that completed unsuccessfully with a reason. Full entry →, carrying a reason such as an Error. Once it is fulfilled or rejected, it is settled No longer pending: a promise has either fulfilled or rejected. Full entry →: its state will not change again. A promise is therefore not the completed value itself. If a function returns a promise, code that calls the function receives an object that describes a future outcome, not a shortcut around waiting for that outcome.
Handlers say what to do after that outcome. promise.then(onFulfilled) registers work for fulfillment, while promise.catch(onRejected) registers work for rejection. A useful chain returns values or promises from each handler, so the next link receives the appropriate eventual value. then() itself returns a new promise. That detail is why a chain can express consecutive steps without nesting one handler inside another. A rejection can come from the original operation, from an explicit throw, or from an error thrown by a handler. Ending a chain with catch() gives one place to handle an unhandled rejection from an earlier link. This lesson uses locally created promises so the model stays separate from the later Fetch/API topic.
async functions and await use the same promise model
Putting async before a function declaration or expression makes an async function. Calling an async function always returns a Promise, even when the body appears to return an ordinary value. If the body returns 42, the returned promise fulfills with 42; if an error escapes the body, the returned promise rejects with that error. The caller can still use .then() and .catch() on the result. This is a common beginner trap: const result = makeLabel() is a promise if makeLabel is async, not the label that its body will later produce.
Inside an async function, await expression evaluates the expression and waits for its promise-like result to settle before continuing that async function. On fulfillment, the await An operator that pauses an async function at an expression until its promise-like operand settles. Full entry → expression produces the fulfillment value. On rejection, it throws the rejection reason at that line. try...catch therefore works naturally around awaited work: put the steps that might reject in try, and decide in catch how to report, recover, or rethrow the error. Handling an error does not mean silently hiding it. A good handler gives useful context or deliberately passes the error onward when the current function cannot make a sound recovery decision. In normal non-module code, await belongs inside an async function; modules also permit top-level await, but module loading is outside this lesson.
Choose ordering from dependencies, not from habit
await makes sequential code readable, but it also means the next awaited expression does not begin until execution reaches it. That is correct when a later step needs the earlier result: compute a student ID first, then use that ID to make a label. It is unnecessarily slow when two tasks are independent. For independent promises, start both operations first and then coordinate their results. Promise.all([first, second]) returns one promise that fulfills with an array of values in the same order as its input when every input fulfills. If an input rejects, the returned promise rejects.
This is not an instruction to run every operation concurrently. Dependencies, resource limits, and error policy determine the appropriate design. The important reasoning step is to ask whether the next operation needs the prior operation's value. If yes, await in sequence. If no, starting work before awaiting can avoid accidental serial delay. In either style, keep the promise boundary visible. Do not write a function that begins asynchronous work and then claim it already has the final value. Return the promise, await it in an async caller, or attach explicit handlers. Those choices make success and failure paths inspectable in tests and easier for a teammate to understand.

Eli explains
The same idea, in plain words
Explain it like I’m 10
Imagine asking a library helper to find a book in storage. You get a claim ticket now, not the book. The ticket is like a Promise: it will later lead to either the book being ready or a notice that something went wrong. You can leave instructions for each outcome. An async function is a helper who works with those tickets. When it uses await, that one helper pauses at a ticket until it is resolved, then continues with the book or handles the problem. Other people in the library can still keep working.
Picture it like this
A Promise is a library claim ticket. .then() is an instruction for what to do when the book arrives; .catch() is an instruction for a problem. await is the helper waiting at that one counter for the ticket's result.
Where the picture stops working
A JavaScript promise is not a physical ticket and does not guarantee a particular time. Also, await pauses an async function's progress, not a person or every task in the program.
Worked example
This Bun-verified program has no network work: async function labelJob() { const label = await Promise.resolve("ready"); return label.toUpperCase(); } labelJob().then(console.log); Promise.reject(new Error("paused")).catch(error => console.log(error.message)); console.log("started");. Bun printed started, then paused, then READY. labelJob() immediately returned a promise, so the program could print started before its awaited fulfillment continuation ran. The separate rejected promise called its catch handler. Inside labelJob, await turned the fulfilled value "ready" into label; the async function's return fulfilled its own promise with "READY".
Key takeaway
Promises make later success and failure explicit. Async functions still return promises; await unwraps a settled result only inside the async function, where try...catch can handle rejection.
Quick check
3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.
What does calling an async function return immediately?
Inside an async function, a Promise used with await rejects. What happens at the await expression?
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related
You’ll learn to
- Define Promise, pending, fulfilled, rejected, and settled.
- Trace a simple promise chain including a rejection handler.
- Explain what
asyncchanges about a function's return value. - Apply
awaitwithtry...catchto handle a rejected operation. - Distinguish sequential work from independent work that may be started together.
Common mistakes
Treating a Promise as if it were already its fulfilled value.
Await it in an async function or attach a fulfillment handler before using its eventual value.
Using
awaitoutside an async function in a normal script.Place it inside an async function; top-level await is a separate module feature.
Handling only success in a chain that can reject.
Add a considered
catch()or usetry...catcharound awaited work.Awaiting independent operations one after another by default.
When their results do not depend on each other, start them first and coordinate with an appropriate promise combinator such as
Promise.all.
Easily confused
fulfilled vs. rejected
A fulfilled promise has a successful value; a rejected promise has a failure reason.
`.then().catch()` vs. `try { await ... } catch ...`
Both handle promise outcomes; the latter lets an async function express the failure path with statement syntax.
sequential awaits vs. Promise.all
Sequential awaits fit dependent steps; Promise.all coordinates promises that can be started independently.
Key vocabulary
- Promise
- An object representing the eventual completion or failure of an asynchronous operation and its resulting value.
- pending
- The initial promise state before it has fulfilled or rejected.
- fulfilled
- The state of a promise that completed successfully with a value.
- rejected
- The state of a promise that completed unsuccessfully with a reason.
- settled
- No longer pending: a promise has either fulfilled or rejected.
- async function
- A function whose call returns a Promise and whose body can use await.
- await
- An operator that pauses an async function at an expression until its promise-like operand settles.
Sources & references
- How to use promises — MDN Web Docs
- Promise — MDN Web Docs
- async function — MDN Web Docs
- await — MDN Web Docs
- ECMAScript Language Specification — Promise Objects — Ecma International / TC39
- ECMAScript Language Specification — Async Function Objects — Ecma International / TC39
EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.
Researched 2026-08-20
Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.

