Course contentsShow
← Node.js
Lesson 219 of 1,9803. Asynchronous Patterns and Flow ControlFree lesson

Transforming Sync Iterators to Async

You will bridge standard synchronous iterables into the asynchronous realm for uniform pipeline processing.

Bridging Synchronous Data to Async Pipelines

In this lesson, you will learn how to wrap standard, synchronous data sources so they can flow seamlessly into your existing asynchronous processing pipelines.

The Compatibility Gap

In modern Node.js, we often build pipelines designed to handle data asynchronously—perhaps fetching from a database or reading from a network socket. However, sometimes we have a simple, synchronous array or a standard Iterator (like one produced by a for...of loop) that we want to inject into these pipelines.

Because asynchronous pipelines expect an AsyncIterator (which returns promises), a standard synchronous Iterator will cause a runtime error if passed directly. We need a "bridge" to normalize this data.

The Transformation Strategy

The most efficient way to transform a sync iterator into an async one is to use an async generator. By wrapping the synchronous values in await or simply yielding them within an async function*, you automatically promote each yielded value into a Promise resolved by the generator.

Consider this bridge:

// A synchronous data source
const syncData = [1, 2, 3];

// The bridge: transforming sync to async
async function* toAsync(syncIterable) {
  for (const item of syncIterable) {
    // Each yield automatically wraps the value in a Promise
    yield await Promise.resolve(item);
  }
}

// Now it fits into your async pipeline!
async function processPipeline() {
  for await (const value of toAsync(syncData)) {
    console.log(`Processing: ${value}`);
  }
}

Why this matters

By normalizing your data sources, you maintain uniformity across your architecture. You no longer need to write two different versions of your processing logic—one for sync arrays and one for async streams. Instead, you "bridge" the sync data at the edge of your pipeline, allowing the rest of your system to rely on the for await...of pattern exclusively. This keeps your error handling and flow control consistent, regardless of whether the source of your data is an in-memory array or a remote API.

Key Takeaway: Use an async generator to wrap synchronous iterables, ensuring they satisfy the AsyncIterator protocol required for uniform pipeline processing.