Best way to slow down generators?

So in a notebook I want debug some code in a generator cell.

Say I have a loop like

{
     for(let i=0;i<10;i++){
       yield i;
     }
}

This is great for seeing what’s going on but javascript is too fast! I want to slow it down so I can see the loop step through but when I throw in a timeout or something with await to force stopping I get the error “async not allowed in generators”.

Whats the best way of going about slowing down execution of a generator in this way?

Give this a try:

{
  for (let i=0;i<10;i++) {
    yield Promises.delay(1000, i);
  }
}

For more, see:

https://beta.observablehq.com/@mbostock/standard-library

2 Likes

Worked beautifully, thanks a ton! The ability to throw yields into intermediate stages makes debugging a dream!

And if you want multiple cells to be precisely synchronized, try Promises.tick instead of Promises.delay:

{
  for (let i = 0; i < 10; ++i) {
    yield Promises.tick(1000, i);
  }
}
1 Like

Cool! I’m assuming that one is based on requestAnimationFrame instead of a timeout?

Promises.delay, Promises.tick and Promises.when all use setTimeout because typically you want to sleep for longer than one animation frame. If you just want to sleep for one animation frame, then yield without any promise is the simplest option:

{
  for (let i = 0; i < 10; ++i) {
    yield i;
  }
}

What makes Promises.tick synchronized is that it uses Promises.when under the hood, which allows multiple promises that want to wake up at the same time to use the same setTimeout internally:

1 Like

Can these ideas be applied to case where you want to periodically sample from an underlying fast generator?

e.g. to update ui that is more sensibly updated at 1 fps rather than 60 fps.

Unlike in the above example I don’t want to slow down the underlying computation, just stream regular snapshots

Blundered my way to this via the Custom Generators writeup,

slowloop = {
let i = 0,
looper;
let slowcoreloop = runSimulation(osc2NodeExample());
for await (looper of slowcoreloop) {
yield { count: i, main: looper };
i++;
await Promises.delay(500);
}
}

Where async function* runSimulation(net) {…etc defines (if I have my terminology right) the generator function. I had trouble using a generator instantiated already in another cell, but this is progress at least…

cleaned up a bit,

Playing with variations, … but this isn’t quite right either


while (true) {
if (coreloop.count % 10 == 0) {
yield coreloop;
}

await Promises.delay(1000);
}