Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

JavaScript Async Functions and Async Iteration

Understand async functions, await, sequencing versus concurrency, asynchronous errors, async iterables, for await...of, async generators, and Array.fromAsync.

Levels: Intermediate ~45 min read

Intermediate

Async functions return Promises

An async function always returns a Promise. Its body can use await, but calling the function does not give you the eventual value directly.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does calling an async function return?

async function answer() { return 42; }
const result = answer();

Returning and throwing inside async functions

A normal return from an async function fulfills its returned Promise. A throw makes that Promise reject. This gives async functions the same Promise-based outcome model used by the previous lesson.

Interactive Runnable example
Edit

Ready to run.

Quick check

What happens to the Promise returned by an async function when its body throws?

async function fail() { throw new Error("x"); }

await unwraps a Promise outcome

Inside an async function, await evaluates an expression and waits for its Promise outcome. If it fulfills, await produces the fulfillment value. If it rejects, await throws that rejection reason at the await point.

Interactive Runnable example
Edit

Ready to run.

Quick check

If the awaited Promise rejects, what does await do?

async function run() {
  await Promise.reject(new Error("no"));
}

await does not block the JavaScript thread

await suspends the current async function until the awaited operation settles. It does not freeze the JavaScript thread or stop unrelated work from running.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does await suspend?

async function run() { await delay(10); }

Sequential awaits

Two awaits written one after another are sequential when the second operation is started only after the first finishes. This is sometimes correct, but it can unnecessarily increase total latency when the operations are independent.

Interactive Runnable example
Edit

Ready to run.

Quick check

Why can independent sequential awaits be slower?

const a = await taskA();
const b = await taskB();

Start independent work before awaiting

When operations are independent, create their Promises first and then await them. Promise.all is often the clearest way to express that all results are required.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which pattern expresses independent operations that should all succeed?

const values = await Promise.all([taskA(), taskB()]);

try/catch around await

Because await turns rejection into a throw at the await point, ordinary try/catch can handle asynchronous failures. Keep the catch boundary close enough to provide useful recovery or context.

Interactive Runnable example
Edit

Ready to run.

Quick check

Why can ordinary try/catch handle an awaited rejection?

async function load() {
  try { await request(); } catch (error) { return "fallback"; }
}

Errors still reject the async function if uncaught

If an async function does not catch a rejection or throw, its returned Promise remains rejected. The caller can choose to catch it with await or with Promise methods.

Interactive Runnable example
Edit

Ready to run.

Quick check

If an async function rejects and the caller does not attach a handler, what exists?

async function load() { throw new Error("failed"); }
const result = load();

Async iterables and async iterators

An async iterable exposes Symbol.asyncIterator and produces an async iterator. Its next() method returns a Promise for an IteratorResult. This lets a consumer receive values over time.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does an async iterator next() return?

const iterator = source[Symbol.asyncIterator]();
const result = iterator.next();

for await...of consumes async iterables

for await...of repeatedly awaits the next result from an async iterator. It is designed for values that arrive asynchronously and also knows how to consume synchronous iterables through the language’s async-from-sync adaptation.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which construct is designed to consume an async iterable one value at a time?

for await (const value of source) {
  use(value);
}

Async generator functions

An async generator combines generator-style pause points with Promise-based asynchronous steps. Calling it creates an async iterator; each next() returns a Promise for the next IteratorResult.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does an async generator call produce?

const pages = async function* () { yield 1; };
const iterator = pages();

Array.fromAsync

Array.fromAsync consumes an async iterable or array-like source and returns a Promise for a new Array. It is useful when you need the complete collection rather than streaming each value yourself.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does Array.fromAsync return?

const values = await Array.fromAsync(source);

Do not confuse async sequencing with cancellation

Starting an async operation and then abandoning its result does not automatically cancel the underlying work. Cancellation is a separate design concern. Browser APIs commonly use AbortSignal and AbortController; that belongs to the web-platform track rather than the ECMAScript Promise model.

Quick check

Does await automatically cancel the underlying operation when its result is no longer needed?

const result = await operation();

Async cleanup and iterator closing

When an async iteration exits early, the async iterator may receive a return() request so it can perform cleanup. This matters when an async generator owns resources or represents a stream that should be closed.

Interactive Runnable example
Edit

Ready to run.

Quick check

What can happen when for await...of exits an async iterator early?

for await (const value of source) {
  break;
}

Awaiting synchronous values

await also accepts ordinary values. A non-Promise value is treated as an already-available fulfillment value, which makes generic async code convenient when a helper may return either a value or a Promise.

Interactive Runnable example
Edit

Ready to run.

Quick check

What happens when await receives a non-Promise value?

async function normalize(value) { return await value; }

Async iteration is not automatic parallelism

A for await...of loop consumes one iterator result at a time. If each iteration awaits another independent operation, those operations are naturally sequenced unless you explicitly collect and coordinate their Promises.

Interactive Runnable example
Edit

Ready to run.

Quick check

Does for await...of automatically run all loop bodies concurrently?

for await (const value of source) { await use(value); }
Interactive Runnable example
Edit

Ready to run.

  • Use async functions when Promise-based control flow becomes easier to read as sequential steps.

  • Await only when you need the result or need the rejection to enter your local error boundary.

  • Start independent operations before awaiting them when their work can safely overlap.

  • Use Promise.all when every result is required; choose other combinators by their outcome contract.

  • Use for await...of when values arrive through the async iterator protocol and should be consumed incrementally.

  • Do not describe await as blocking the JavaScript thread; it suspends the current async continuation.

  • Do not assume that dropping a Promise or leaving an async loop cancels arbitrary underlying work.

  • Keep browser-specific cancellation, fetching, and event-loop scheduling details in the web-platform lessons.

Practice: trace the async flow

Build a small async pipeline that starts two independent operations, combines their results, handles one failure path, and then consumes a short async generator. Explain where execution is suspended and where independent work overlaps.

Specification references

The normative language rules for this lesson come from the living ECMAScript specification. Browser-specific scheduling and cancellation APIs will be covered separately in the web-platform track.

ECMA-262 — Async Function Definitions

ECMA-262 — Async Iterator Interface and Async-from-Sync Iterators

ECMA-262 — for-await-of and iteration statements

ECMA-262 — Array.fromAsync

Was this page helpful?

Mark this learning resource complete to track your learning progress.