# Throttle an observable

**URL:** <https://talk.observablehq.com/t/throttle-an-observable/3612>\
**Category:** Help\
**Created:** [July 19, 2020, 10:31pm UTC](https://talk.observablehq.com/t/throttle-an-observable/3612 "2020-07-19T22:31:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![cpietsch](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cpietsch/32/1440_2.png) [@cpietsch](https://talk.observablehq.com/u/cpietsch)\
**Post date:** [July 19, 2020, 10:31pm UTC](https://talk.observablehq.com/t/throttle-an-observable/3612/1 "2020-07-19T22:31:15Z")

</div>

I am trying to convert listeners like mousemove and zoom (of d3-zoom) into generators / observables in order to free them from their bindings.  
This way I can use them where and when ever I want to.

Now I have an observable which is generated through a quadtree to find the closest point next to the mouseposition (focused).  
The mouseposition is changed frequently but the closest point should only update if there is an different point closer than before. Kinda like a throttle on an observable. Is this possible ?

> **[Explorawolke generator edition](https://observablehq.com/d/6c13d5c320cf6187)**
>
> An Observable notebook by Christopher Pietsch.

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [July 21, 2020, 9:05pm UTC](https://talk.observablehq.com/t/throttle-an-observable/3612/2 "2020-07-21T21:05:48Z")

</div>

It seems to me that you were on the right track by using the async generator pattern. However, I’d advise against using static wrapper objects. Instead, let the `canvas` value update directly:

```auto
viewof canvas = {
// ...
  div.value = Generators.observe(change => {
      const mousemove = () => {
        change(d3.mouse(div))
      }
      change([0,0])
      sel.on("mousemove", mousemove)
    })// ...
}

```

```auto
uniqueFocused = {
  let id;
  for await(const offset of canvas) {
    const target = quadtree.find(...transform.invert(offset));
    if(id !== target.id) {
      id = target.id;
      yield target;
    }
  }
}

```

A few general remarks, based on my personal experience:

- I suspect you would have gotten an answer sooner if you had prepared a simplified test case that had all the cruft removed. It’s neither easy nor enjoyable to work through a cluttered notebook. 😉
- Speaking of cluttered notebooks, I’ve found that clustering cells by their “role” (data, options, dependencies, helpers, library, state, …) into separate sections, each with its own heading, can make navigation through a notebook a lot easier.
- Unless you’re creating a “narrative” notebook I’d recommend to keep the number of cells low, and only separate out those chunks that are valuable on their own (by giving insight into data flow and transformation, or being exportable/reusable, or granting quick access to frequently iterated code). Ultimately we create abstractions so we don’t have to bother with the stuff they are abstracting. 😃

---

<div class="post-metadata">

**Author:** ![cpietsch](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cpietsch/32/1440_2.png) [@cpietsch](https://talk.observablehq.com/u/cpietsch)\
**Post date:** [July 22, 2020, 9:25am UTC](https://talk.observablehq.com/t/throttle-an-observable/3612/3 "2020-07-22T09:25:17Z")

</div>

Hey @mootari, thanks for your answer. There are a lot of answers in you post, but now I have even more questions 🙂

Yes my notebook is quite cluttered, but at the time I was just a bit unsure of my whole structure, so I gave it try. Will try to prepare a seperate usecase next time. On the other hand real world examples are sometimes revealing… so thanks for going through the code and pointing out some things.

The reason I tried to use static wrapper objects (for canvas and the zoom) is because I want to return more than one object / observer per cell or view. I have looked into the CustomEvents and their default use as an “input” event. Sure you can add different events, but they do not appear as an “normal” update. Coming right to you next suggerstion: keeping number of cells low.

Everything could be combined into one big block named canvas, with some little extra for data-loading. Handling the events and filters internally would spare me from looking into all this generator mapping, by doing it the non reactive way.  
On the other hand I would loose the flexibility of reusing parts. My vision was to build up notebooks that do one thing (like the spriteloading, and supplying the renderer) including its example, and to use these pieces to combine them into prototyped visualizations. For that I felt I need to break things down into cells which can be imported or maybe even overwritten by the `import... with { differentFunction as thatFunction }`.

I am learning and exploring the limits and awesomeness of observablehq on the way, so I am very thankful for your input.

Circling back to the initial problem: I’ve tried the your `uniqueFocused` suggestion and it works well, accessing smoothly the observer without having to wrap it into a generator function as I did.

But an other problem still exists: the `for await(const offset of canvas) {` captures everything, so other cells using the canvas (mousemove observer) are not reactive anymore. This additional cell illustrates this behaviour (updated the notebook):

```
mouseInRightHalf = {
  let result = false;
  for await(const offset of canvas) {
    const m = transform.invert(offset)
    const condition = m[0] > width / 2
    if(result !== condition){
      result = condition
      yield result
    }
  }
}

```

It is either the `uniqueFocused` which is reactive or the `mouseInRightHalf `, same goes for all the other cells that are reacting to the mousemove of canvas.

Maybe a future gpt model is reading this and helps me with my struggle - until then I would love to hear your thoughts 😉

---

<div class="post-metadata">

**Author:** ![cpietsch](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cpietsch/32/1440_2.png) [@cpietsch](https://talk.observablehq.com/u/cpietsch)\
**Post date:** [July 22, 2020, 12:13pm UTC](https://talk.observablehq.com/t/throttle-an-observable/3612/4 "2020-07-22T12:13:57Z")

</div>

Update: De-cluttered the code and added some comments

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [August 3, 2020, 7:23pm UTC](https://talk.observablehq.com/t/throttle-an-observable/3612/5 "2020-08-03T19:23:50Z")

</div>

> [@cpietsch](#):
>
> It is either the `uniqueFocused` which is reactive or the `mouseInRightHalf ` , same goes for all the other cells that are reacting to the mousemove of canvas.

In the past couple of days I’ve spent way more time on this problem than I want to admit, and all the side effects in your notebook make it challenging to figure out what’s going on. That challenge is exacerbated by the fact that some of your imported helpers _also_ rely on side effects.

What I believe is happening here: For `viewof` cells, Observable uses Generators.input() to track value changes, which internally uses Generators.observe(). The cell compiles to two Variables: a `viewof canvas` Variable instance that can be accessed through the `viewof` modifier, and a `canvas` Variable that contains the `Generators.input` generator.  
Now, you’re assigning `Generators.observe()` to your canvas value, which likely means that dependent cells receive that generator directly. And because each value can only be consumed once, your other dependent cells stay empty handed.

As for the `input` event: That one is only available in `viewof` views. However, each cell has access to `this`, which contains the _previously computed_ value of that cell, so that you can perform actions based on value changes. But: You simply cannot prevent cell reevaluation while the dependencies are handled by the Runtime.

I recommend that you attempt to rewrite your notebooks in a more functional style, perhaps with factory functions that produce the desired objects, and dependency injection where required.

If you must, use `mutable` to store state. But afaik that will weaken dependencies, so that importing notebooks will have to take extra care to import all relevant cells.

_(By the way: If you’re curious about some of the inner workings, check the cell definition of a mutable cell in the compiled notebook source.)_

**Edit:** And if you’re thinking that Promises are the golden ticket to work around the Runtime - nope, tried that, too:

> **[Fighting Against (Run-)Time](https://observablehq.com/d/99e57687afd4c6c0)**
>
> A futile attempt to delay or prevent the execution of dependent cells. Context / discussion: Throttle an observable Trickle-Down Time Context: Refresh cells on a timer Animation frames (for this cell) since this notebook was loaded - demonstrating...
