DEV Community

Aleksei Berezkin
Aleksei Berezkin

Posted on • Updated on

 

How to split up CPU-intensive work with async generators

So you have some large amount of work to be done. Perhaps you prepare some heavy API answer, or parse a large document, or compute vertices for your 3d scene. Something like this:

function computeVertices() {
  const vertices = []
  for (let i = 0; i < 10_000_000; i++) {
    vertices.push(computeVertex(i))
  }
  return vertices
}
Enter fullscreen mode Exit fullscreen mode

This code works 200ms, the UI looks unresponsive, scrolls are jumping, and transitions are jarred — all the UX is terrible. Is there a nice way to make pauses during this work? Yes! Async generators to the rescue.

That's how it looks:

async function computeVertices() {
  const workLimiter = createWorkLimiter()
  const vertices = []
  for (let i = 0; i < 10_000_000; i++) {
    await workLimiter.next()
    vertices.push(computeVertex(i))
  }
  return vertices
}
Enter fullscreen mode Exit fullscreen mode

And here's implementation:

async function* createWorkLimiter(
  work = 10,
  pause = 6,
) {
  let start = Date.now()
  for ( ; ; ) {
    yield
    if (Date.now() >= start + work) {
      await delay(pause)
      start = Date.now()
    }
  }
}

function delay(ms) {
  return new Promise(resolve =>
    setTimeout(resolve, ms)
  )
}
Enter fullscreen mode Exit fullscreen mode

Cool, isn't it?

Top comments (0)

Create an Organization Let's hear from your organization

Create an Organization and start sharing content with the community on DEV.