# Observable 2.0 Generators Corollary

**URL:** <https://talk.observablehq.com/t/observable-2-0-generators-corollary/10847>\
**Category:** Feedback\
**Created:** [September 13, 2026, 9:29pm UTC](https://talk.observablehq.com/t/observable-2-0-generators-corollary/10847 "2026-09-13T21:29:38Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![MarioDelgadoSr](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mariodelgadosr/32/1828_2.png) [@MarioDelgadoSr](https://talk.observablehq.com/u/MarioDelgadoSr)\
**Post date:** [September 13, 2026, 9:29pm UTC](https://talk.observablehq.com/t/observable-2-0-generators-corollary/10847/1 "2026-09-13T21:29:38Z")

</div>

The official [Upgrading to Notebooks 2.0 Guide (§ Generators)](https://observablehq.com/@observablehq/upgrading-to-notebooks-2-0#generators) details how generator cells are converted in 2.0 using explicit generator functions or [IIFEs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) (`async function*`).

A practical variation of this pattern occurs when using event streams like `Generators.queue()` to create reactive filters (e.g., listening to a [Vega-Lite `brush` or `brush_x` signal on a `barChart`](https://observablehq.com/d/bdaff8d135b0c357)).

The notebook [Generators in Observable 2.0](https://observablehq.com/@observablehq/upgrading-to-notebooks-2-0#generators) illustrates a simple workaround using _**[for await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of):**_

```javascript
filter1 = {
    const eventStream = Generators.queue((notify) => {
    notify("a");
    });

    // ❌ WORKED IN 1.0; BROKEN IN 2.0:
    for (const value of eventStream) {
    let filters = await value;
    // Perform any optional processing before re-yielding to the notebook
    yield filters;
    }
}

```

```javascript
filter2 = {
    const eventStream = Generators.queue((notify) => {
    notify("a");
    });

    // ✅ FIXED IN 2.0 BY SIMPLY ADDING 'await':
    for await (const value of eventStream) {
    let filters = await value;
    // Perform any optional processing before re-yielding to the notebook
    yield filters;
    }
}

```

---

<div class="post-metadata">

**Author:** ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)\
**Post date:** [September 13, 2026, 10:31pm UTC](https://talk.observablehq.com/t/observable-2-0-generators-corollary/10847/2 "2026-09-13T22:31:31Z")

</div>

Yes, that’s right, although you don’t need the inner `await` within the for-await loop.

So before it was:

```auto
for (const promise of generator) {
  const value = await promise;
  console.log(value);
}

```

And now it is:

```auto
for await (const value of generator) {
  console.log(value);
}

```

See [for await…of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) and [async function\*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*).

The reason for this change is that Old Observable’s generators predate widespread browser support for async generators, and hence they were implemented as (synchronous) generators that yield promises. Since browsers now widely support asynchronous generators, New Observable uses that. (You can compare the [new implementation](https://github.com/observablehq/notebook-kit/blob/main/src/runtime/stdlib/generators/observe.ts) to the [old implementation](https://github.com/observablehq/stdlib/blob/main/src/generators/observe.js).)

Perhaps we should add backwards compatibility for this difference in behavior in the 2018 standard library in New Observable… but I was hoping that the distinction was small enough to not be worth the trouble.
