Skip to content

Latest commit

 

History

History
85 lines (60 loc) · 1.85 KB

coroutine.md

File metadata and controls

85 lines (60 loc) · 1.85 KB

Coroutine

rsxjs comes with a built-in coroutine runtime that can be used instead of async/await when cancelation is required. It automatically wraps routines in a deferral component & attaches a cancel method to the returned promise.

Notes

  • No synchronous cancelations.
  • First argument is always a defer() function (see deferral docs).

Synchronous Cancelation

Coroutines cannot be cancelled synchronously since it would be a poor design to immediately cancel a scheduled operation. Let's take this code as an example:

import { co } from 'rsxjs'

const p = co(function* () {
  // start doing work
})

if (shouldNotHaveRun) {
  await p.cancel()
}

await p

This can easily be refactored to never schedule the operation in the first place:

import { co } from 'rsxjs'

if (!shouldNotHaveRun) {
  await co(function* () {
    // start doing work
  })
}

As you can see, the second one is much cleaner & does not require extra logic from the runtime to allow immediate cancelation.

Usage

API is based on its cousin co.

  • co(fn): executes fn on next tick.
  • co.wrap(fn): wraps the function and provides an async function back.

Examples

Operating on a file

import * as net from 'net'
import { Deferral, makeChan, range } from 'rsxjs'
import { open, close } from 'mz/fs'

const p = co(function* (defer) {
  const fd = yield open(file)
  defer(() => close(fd))

  const socks = makeChan({ bufferSize: 100 })
  const server = net.createServer(sock => socks.put(sock))

  // doesn't return a promise right now, but
  // you get the idea
  await server.listen(fd)
  defer(() => server.close())

  for await (const sock of socks) {
    // do something with the sock
  }
})

// cancel it whenever
await p.cancel()

// p is a promise, you can await it or whatever
await p