# Intro example bug: previous cells continue running

**URL:** <https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550>\
**Category:** Feedback\
**Created:** [March 26, 2018, 8:16am UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550 "2018-03-26T08:16:51Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![shaunlebron](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/shaunlebron/32/81_2.png) [@shaunlebron](https://talk.observablehq.com/u/shaunlebron)\
**Post date:** [March 26, 2018, 8:16am UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550/1 "2018-03-26T08:16:51Z")

</div>

In the last example here, the animation code continues running on previous versions of the cells:

> **[Introduction to Asynchronous Iteration](https://observablehq.com/@mbostock/introduction-to-asynchronous-iteration)**
>
> Observable now supports asynchronous iteration, an exciting new feature of ES2018 that was finalized last month by TC39! You’ll need a very recent browser to run this notebook, such as Chrome 63+, Firefox 57+ or Safari Technology Preview 48....

You can see this in the console by replacing with the following code:

```
{
  const w = Math.min(640, width);
  const h = 320;
  const r = 20;
  const t = 1500;
  const svg = d3.select(DOM.svg(w, h));
  const circle = svg.append("circle").attr("r", r).attr("cx", w / 4).attr("cy", h / 4);
  yield svg.node();
  let i=0;
  while (true) {
    console.log("loop", i++); // <-- continues printing
    await circle.transition().duration(t).attr("cy", h * 3 / 4).end();
    await circle.transition().duration(t).attr("cx", w * 3 / 4).end();
    await circle.transition().duration(t).attr("cy", h * 1 / 4).end();
    await circle.transition().duration(t).attr("cx", w * 1 / 4).end();

    // quickfix: stop the loop of our node has been unmounted (i.e. parentElement is null)
    if (!svg.node().parentElement) break;
  }
}

```

I noticed this was warned against here when mentioning the difficulty of cleaning up timeouts:

> **[Observable anti-patterns and code smells](https://observablehq.com/@tmcw/observable-anti-patterns-and-code-smells)**
>
> Here are a few things that you might do a bunch in JavaScript ‘in general’ but are often more trouble than they're worth within in the context of Observable. Table of contents Timers: use them sparingly, a lot of times there’s a better way Mutation:...

I’m making use of the quickfix above so I can stop the loop by detecting when the element is no longer mounted.

---

<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:** [March 26, 2018, 3:40pm UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550/2 "2018-03-26T15:40:59Z")

</div>

Yes, this was a bug in the example which I’ve now fixed. Thank you for the report. (Arguably it’s “fine” in the sense it works if the cell is never re-evaluated, but it should still be considered an antipattern.)

The problem is that promises are not cancellable, so there’s no way for the Observable runtime to cancel an asynchronous function that goes into an infinite loop as this one did.

Your fix works, but I chose instead to move the `yield` inside the infinite loop. Unlike promises, generators are cancellable and are terminated automatically by the Observable runtime using [_generator_.return](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Generator/return).

In the near future, we’re planning on implementing an `invalidation` promise in the [standard library](https://github.com/observablehq/notebook-stdlib) that would resolve when a cell’s definition or inputs change. This would replace [Promises.never](https://github.com/observablehq/notebook-stdlib/blob/master/README.md#Promises_never) (which [leaks](https://github.com/observablehq/notebook-stdlib/issues/12)) and provide a new mechanism for [disposing of resources](https://beta.observablehq.com/@mbostock/disposing-content) when a cell is re-evaluated.

---

<div class="post-metadata">

**Author:** ![shaunlebron](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/shaunlebron/32/81_2.png) [@shaunlebron](https://talk.observablehq.com/u/shaunlebron)\
**Post date:** [March 26, 2018, 5:25pm UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550/3 "2018-03-26T17:25:17Z")

</div>

> Unlike promises, generators are cancellable

That’s a great description that cleared up a lot of my confusion. I want to stick my neck out and say that I find all these yields and awaits and promises to be _very_ confusing. I think just showing a simple contrived example like this could go a long way to help clarify what’s going on:

```
{
  yield "foo"; // set cell value to "foo"
  await Promises.delay(1000); // wait 1 second
  yield "bar"; // set cell value to "bar"
}

```

As a side note, I’ve always wondered how to cancel async functions—like Unity’s [StopCoroutine](https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopCoroutine.html). I’m glad to see that `yield` acts as a safe way for async functions to sprinkle safe spots to pull the plug so to speak.

Maybe it’s worth mentioning that async cells can only be interrupted at `yield` points?

---

<div class="post-metadata">

**Author:** ![jashkenas](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jashkenas/32/1778_2.png) [@jashkenas](https://talk.observablehq.com/u/jashkenas)\
**Post date:** [March 26, 2018, 10:24pm UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550/4 "2018-03-26T22:24:17Z")

</div>

Mike shipped the `invalidation` promise this afternoon:

> **[Invalidation](https://observablehq.com/@mbostock/disposing-content)**
>
> An Observable notebook.

… so you can now clean up whatever you need to (timers, mutated DOM, external stateful libraries) before the cell is re-evaluated:

```auto
{
  var resource = library.allocSomethingBig();
  invalidation.then(() => {
    resource.dispose();
  });
  return resource;
}

```

---

<div class="post-metadata">

**Author:** ![shaunlebron](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/shaunlebron/32/81_2.png) [@shaunlebron](https://talk.observablehq.com/u/shaunlebron)\
**Post date:** [March 27, 2018, 4:57am UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550/5 "2018-03-27T04:57:02Z")

</div>

I might start using this pattern if I want to cancel long async functions:

```
{
  const w = Math.min(640, width);
  const h = 320;
  const r = 20;
  const t = 1500;
  const svg = d3.select(DOM.svg(w, h));
  const circle = svg.append("circle").attr("r", r).attr("cx", w / 4).attr("cy", h / 4);
  let i=0;
  const tick = () => console.log(i++);

  // use `yield await` to allow the animation to be canceled
  async function* anim() {
    yield await circle.transition().duration(t).attr("cy", h * 3 / 4).end(); tick();
    yield await circle.transition().duration(t).attr("cx", w * 3 / 4).end(); tick();
    yield await circle.transition().duration(t).attr("cy", h * 1 / 4).end(); tick();
    yield await circle.transition().duration(t).attr("cx", w * 1 / 4).end(); tick();
  }

  yield svg.node();
  while (true) {
    for await (let step of anim()) {
      yield svg.node(); // yield after every step
    }
  }
}

```

Overkill for this simple case, but good to know I can do this when needed.

---

<div class="post-metadata">

**Author:** ![jrus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jrus/32/586_2.png) [@jrus](https://talk.observablehq.com/u/jrus)\
**Post date:** [May 22, 2018, 7:32am UTC](https://talk.observablehq.com/t/intro-example-bug-previous-cells-continue-running/550/6 "2018-05-22T07:32:43Z")

</div>

I was looking at,

> **[Variable Speed Generator](https://observablehq.com/@mbostock/variable-speed-generator-test)**
>
> An Observable notebook by Mike Bostock.

and noticed it uses `invalidation`, whereas,

> **[Synchronized Views](https://observablehq.com/@mbostock/synchronized-views)**
>
> An Observable notebook by Mike Bostock.

uses `Generators.disposable`. I don’t quite understand the intended uses of these two, or when we should prefer or the other in idiomatic usage.
