Jak rozdělit práci náročnou na CPU s asynchronními generátory

Čeká vás tedy velké množství práce. Možná si připravíte nějakou těžkou odpověď API nebo analyzujete velký dokument nebo vypočítáte vrcholy pro vaši 3D scénu. Něco takového:

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

Tento kód funguje 200 ms, uživatelské rozhraní vypadá, že nereaguje, posouvání přeskakuje a přechody jsou roztřesené – veškeré uživatelské prostředí je hrozné. Existuje nějaký pěkný způsob, jak dělat pauzy během této práce? Ano! Asynchronní generátory na záchranu.

Takhle to vypadá:

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
}

A tady je implementace:

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

function delay(ms) {
  return new Promise(resolve =>
    setTimeout(resolve, ms)
  )
}

Skvělé, že?