A Task is a composable unit of asynchronous work. You can build a blueprint of asynchronous steps using Task operations like map and chain, and then run the blueprint using runTask to get the Task's result.
Tasks are:
- Lazy: they only execute when their result is demanded with
runTask. - Single-consumer: they don't cache their result: they execute and produce a new result each time you pass them to
runTask.
Running a Task returns a pair: [killTask, futureValue]:
killTask :: () -> void: function to abort the Task. If called before the Task finishes,futureValuewill remain pending forever.futureValue :: FutureValue a: FutureValue representing the Task's result.
A FutureValue is a value that becomes known at a particular time, for example, when a Task completes. Once a FutureValue's time and value become known, they are immutable.
In contrast to Tasks, FutureValues are:
- Strict (eager): you don't need to poke a FutureValue for it to receive a value.
- Multi-consumer: they are immutable once set, caching their value and arrival time once known. You can safely cache FutureValues, give them to multiple consumers, etc.
type Resolver a = ((a -> ()) -> Kill: function to set a Task's result, and return a Kill that can be used to kill the Task while it is still in flight.type Kill = { kill :: () -> () }: object with akillmethod to kill an in-flight Task.
Execute a Task. This forces a Task to execute immediately, returning a Kill that can be used to kill the Task, and a FutureValue representing the Task's eventual result.
Create a Task that will produce a result by running a resolver function.
import { task, killWith } from 'yafi'
const [killTimeout, futureValue] = task(resolve => {
return killWith(clearTimeout, setTimeout(resolve, 1000, 'hello world'))
})Transform a Task's eventual result.
Given a Task that will produce a value and a Task that will produce a function, create a Task that will apply the function to the value and produce the result.
Combine two Tasks to produce a new one.
Create a new Task by chaining more work onto an existing one. The provided function takes the original Task's result as input and returns a new Task.
Given two Tasks, return a Task equivalent to the one that produces a result earlier, automatically killing the Task that loses the race.
Helper to create a Kill instance whose kill method calls the provided function with the provided state.
const killTimeout = killWith(clearTimeout, setTimeout(x => console.log(x), 1000, 'Hi!'))
killTimeout.kill() // Hi! is never loggedCombine two Kills into one that kills both.
const killTimeout1 = killWith(clearTimeout, setTimeout(x => console.log(x), 1000, 'Hello'))
const killTimeout2 = killWith(clearTimeout, setTimeout(x => console.log(x), 2000, 'World'))
const killTimeouts = killBoth(killTimeout1, killTimeout2)
killTimeouts.kill() // Neither Hello nor World will be loggedTransform a FutureValue's value, without changing its arrival time.
Return a FutureValue that is equivalent to the earlier of two FutureValues