# Promises.tick and (relatively) heavy computations

**URL:** <https://talk.observablehq.com/t/promises-tick-and-relatively-heavy-computations/1798>\
**Category:** Help\
**Created:** [March 21, 2019, 11:53am UTC](https://talk.observablehq.com/t/promises-tick-and-relatively-heavy-computations/1798 "2019-03-21T11:53:55Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Job](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/job/32/1185_2.png) [@Job](https://talk.observablehq.com/u/Job)\
**Post date:** [March 21, 2019, 11:53am UTC](https://talk.observablehq.com/t/promises-tick-and-relatively-heavy-computations/1798/1 "2019-03-21T11:53:55Z")

</div>

Hey, a (hopefully) quick question to clarify. The following example is taken from [https://observablehq.com/@mbostock/animation-loops](https://observablehq.com/@mbostock/animation-loops)

```auto
{
  let i = 0;
  while (true) {
    yield Promises.tick(1000, ++i);
  }
}

```

Imagine if I was instead performing a heavy computation in the while loop, say one that takes 50ms on average, and I want to yield every 100 ms. If I try to implement that naively in the while loop, would the result be one tick every 150 ms or every 100 ms? In case of the former, what is the right way to ensure a constant tick rate?

I’m asking because in [this little notebook on randomly answering multiple choice tests](https://observablehq.com/@jobleonard/when-answering-a-multiple-choice-test-at-random-how-many-ans), the amount of samples I take every loop grows exponentially:

```auto
    const iterations = 10**(Math.log10(totalSamples)|0);
    for(let j = 0; j < iterations; j++){
      let correct = 0;
      // answer totalQuestions questions at random
      for (let i = 0; i < totalQuestions; i++){
        if (randVals[--remainingVals] < correctChoice) correct++;
        // generate new random values if we run out
        if (remainingVals === 0) {
          window.crypto.getRandomValues(randValsU8);
          remainingVals = randVals.length;
        }
      }
      rawData[correct]++;
      totalSamples++;
    }

```

The effect is nice, but for the last few loops I figure it might get a bit heavy, so I was curious what the best way to deal with that would be (I could use a worker but that is probably overkill).

---

<div class="post-metadata">

**Author:** ![bgchen](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/bgchen/32/784_2.png) [@bgchen](https://talk.observablehq.com/u/bgchen)\
**Post date:** [March 21, 2019, 2:49pm UTC](https://talk.observablehq.com/t/promises-tick-and-relatively-heavy-computations/1798/2 "2019-03-21T14:49:13Z")

</div>

If you have something which always takes `X` ms inside your while loop and `yield Promises.tick(Y, result)` then if `X < Y` it should (after the first loop) tick every `Y` ms. If `X > Y` then the delay time will be rather more complicated: I think it’s `X + Y - (X % Y)` (?). If you can ensure that the other code in your loop will always run in less than 100 ms you should get a roughly constant tick rate.

Another approach is to save `Date.now` to a temporary variable `lastYielded` after each yield and then loop until `Date.now` is greater than `lastYielded+100` before yielding again:

```auto
{
  const delay = 100;
  let i = 0;
  let lastYielded = Date.now();
  while (true) {
    while (Date.now() < lastYielded + delay) {
      // do stuff
      i++;
    }
    yield i;
    i = 0;
    lastYielded = Date.now();
  }
}

```

---

<div class="post-metadata">

**Author:** ![Job](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/job/32/1185_2.png) [@Job](https://talk.observablehq.com/u/Job)\
**Post date:** [March 21, 2019, 6:51pm UTC](https://talk.observablehq.com/t/promises-tick-and-relatively-heavy-computations/1798/3 "2019-03-21T18:51:12Z")

</div>

Thanks, that clarifies it 🙂
