Coroutine

Coroutines are implemented using generator functions. A generator function allows you to pause the execution of a function at any point and later resume it from where it left off. This is done using the yield keyword.

function* myGenerator() {
  console.log("Start")
  yield  // Pause till next() is called
  console.log("Resumed")
  yield  // Pause again
  console.log("End")
}

const co = myGenerator()
co.next() // Start
co.next() // Resumed
co.next() // End

receive values from generator functions

function* myGenerator() {
  yield 1
  yield 2
  yield 3
}

const co = myGenerator()
console.log(co.next())
console.log(co.next())
console.log(co.next())
console.log(co.next())

Expected output:

{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }

send values to generator functions

function* myGenerator() {
  console.log(yield 1)
  console.log(yield 2)
}

const co = myGenerator()
const val1 = co.next().value
const val2 = co.next(val1 * 2).value
co.next(val2 * 2)

Expected output:

2
4

what about yielding functions

function* myGenerator() {
  yield (cb) => setTimeout(cb, 1000)
  console.log('done')
}

const co = myGenerator()
const fn = co.next().value
fn(() => co.next())

We just eliminated callback hell!

make it more useful

A simple coroutine runner:

function run(generator) {
  const co = generator()

  function next(value) {
    const { value: fn, done } = co.next(value)
    done || fn((err, result) => next([err, result]))
  }

  next()
}

We can use it like this:

const delay = time => cb =>
  setTimeout(cb, time)

const asyncDouble = value => cb =>
  setTimeout(() => cb(null, value * 2), 1000)

function* myGenerator() {
  yield delay(1000)
  console.log('1 seconds passed')
  const [_, value] = yield asyncDouble(2)
  console.log(value)
}

run(myGenerator)

you can do more

What about yielding multiple functions?

What about yielding a nother generator?

What about yielding promises?

That is just async/await:

async function fetchData() {
  const response = await fetch('https://pokeapi.co/api/v2/pokemon/ditto')
  const data = await response.json()
  console.log(data)
}