Symbol.asyncIterator

Marks the method that makes an object usable with for await...of.

Signature
Symbol.asyncIterator
// as implemented on an object:
[Symbol.asyncIterator]()
  • Added in JavaScript ES2018

Return value

symbolThe well-known symbol used as the property key for an object's default async iterator method. The method must return an async iterator whose next() yields promises of { value, done }.

Errors

for await...of throws a TypeError if neither [Symbol.asyncIterator] nor [Symbol.iterator] is present or callable.

Changelog

  • PHP ES2018Introduced together with async generators and the for await...of statement.

Symbol.asyncIterator is the asynchronous counterpart of Symbol.iterator. for await...of looks this key up first; the method returns an async iterator whose next() hands back a promise for { value, done }, and the loop awaits each one before running the body.

When to reach for it

Use it for sequences whose items arrive over time or need I/O between them: paginated API results, lines from a socket, events from a queue, or anything you would otherwise express as a callback loop. An async generator method — async *[Symbol.asyncIterator]() { … } — is the shortest correct implementation, and lets you await freely between yields.

What trips people up

for await...of falls back to Symbol.iterator when no async iterator exists, awaiting each yielded value — so a bug where you defined the wrong key can look like it works over an array of promises. Backpressure is manual: values are pulled one at a time, and nothing buffers ahead unless you write that yourself. And a break or a thrown error calls the iterator's return(), so put cleanup in a finally block inside the generator or it will leak.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Walk a paginated HTTP endpoint page by page without collecting everything first
  • Consume messages from a queue or socket as they arrive
  • Poll a source on a timer and expose it as a normal loop

Frequently asked questions

What is the difference between Symbol.iterator and Symbol.asyncIterator?

Symbol.iterator returns values synchronously for for...of, while Symbol.asyncIterator returns promises of values for for await...of. Implement the async version when producing each item requires I/O or a delay.

Can for await...of iterate an ordinary array?

Yes. When no Symbol.asyncIterator exists it falls back to Symbol.iterator and awaits each yielded value, which is why an array of promises works with for await...of.

How do I clean up when the consumer breaks out of the loop?

Wrap the body of your async generator in try/finally; break, return and thrown errors all call the iterator's return(), which runs the finally block.

More examples

Paging a source until it is exhausted

Each page is awaited before its items are yielded, and the empty page ends the sequence — the loop collects ["a", "b", "c"] without ever holding more than one page.

Example · javascript
const pages = [["a", "b"], ["c"], []];
const feed = {
  async *[Symbol.asyncIterator]() {
    for (const page of pages) {
      await new Promise((r) => setTimeout(r, 5)); // stands in for a fetch
      if (page.length === 0) return;
      yield* page;
    }
  },
};

const all = [];
for await (const item of feed) all.push(item);
console.log(all);

Cleanup runs when the loop breaks early

Breaking out of the loop calls the async iterator's return(), which resumes the generator at its finally block — "iterator closed" prints before "after loop", even though the while(true) never ends on its own.

Example · javascript
const source = {
  async *[Symbol.asyncIterator]() {
    try {
      let n = 0;
      while (true) yield ++n;
    } finally {
      console.log("iterator closed");
    }
  },
};

for await (const n of source) {
  console.log(n);
  if (n === 2) break;
}
console.log("after loop");

Discussion

  • Be the first to comment on this lesson.