API - YannickDot/Taskorama GitHub Wiki

Instance methods

constructor

// create a Task
const myTimeoutTask = Task(function (reject, resolve) {
  let timer = setTimeout(function () {
    resolve(42) // complete task succesfully with value '42' after 3s
  }, 3000)

  // execute `cancel` to stop the timeout
  let cancel = () => clearTimeout(timer)
  return {cancel}
})

.fork(errorEffect, successEffect)

myTimeoutTask
  .fork(console.error, console.log)
// logs : 42

.run(successEffect)

.run(myCb) is an alias for .fork(console.error, myCb)

myTimeoutTask
  .run(console.log)
// logs : 42

.map()

myTimeoutTask
  .map(x => x * 2)
  .fork(console.error, console.log)
// logs : 84

.ap()

Task.of(x => x * 2)
  .ap(Task.of(42))
  .fork(console.error, console.log)
// logs: 84

.chain() / .flatMap()

myTimeoutTask
  .chain(val => Task.of(val * 2))
  .flatMap(val => Task.of(val + 1))
  .fork(console.error, console.log)
// logs: 85

.then()

myTimeoutTask
  .then(x => x * 2)
  .then(val => Task.of(val + 1))
  .fork(console.error, console.log)
// logs: 85

.catch()

myTimeoutTask
  .then(x => {
    throw 'argh'
  })
  .then(x => 42)
  .catch(err => "Cool, it's fine now.")
  .fork(console.error, console.log)
// logs: "Cool, it's fine now."

Static methods

Task.of / Task.resolve

Creates a task that completes immediately with the passed value.

const task = Task.of(200)
task.fork(console.error, console.log)
// logs: 200

Task.reject

Creates a task that rejects immediately with the passed value.

const task = Task.reject(404)
task.fork(console.error, console.log)
// logs error: 404

Task.do(* generatorFn)

Using JavaScript's generators to introduce a synchronous-looking syntax for chaining Tasks. This is inspired by Async/Await for Promises and Haskell's do notation for Monads.

const fetchJSON = url => Task.fetch(url).then(r => r.json())

const main = Task.do(function *() {
  const posts = yield fetchJSON('/posts')
  const users = yield fetchJSON('/users')

  yield Task.wait(2000) // Lets pause for 2 sec.

  return {posts, users}
})
// -> 'main' is a Task

main
  .fork(console.error, console.log)

// -> logs: { posts: [...],  users: [...] }

Task.fetch(url) (browser only)

Creates a task that makes a request on the specified url. It resolves with a Response object.

The Response object exposes the following readers at the moment :

  • .json()
  • .text()

Task.fetch try to mimic the behavior of the fetch API

const url = 'https://jsonplaceholder.typicode.com/users'
const requestTask = Task.fetch(url)
  .then(response => response.json())

const runningRequest = requestTask.fork(console.error, console.log)
// logs: [Object, Object, ..., Object]

Any inflight request can be cancelled like this :

runningRequest.cancel()

Task.runInWorker

Creates a task that run code inside a WebWorker and resolves/rejects with the result from the worker.

const workerTask = Task.runInWorker(
  done => {
    // Inside a new web worker!
    const msg = 'Hello from a worker!'
    
    // Call done to end worker and send result to main thread
    done(msg)
  }
)

workerTask.fork(console.error, console.log)
// logs : 'Hello from a worker!'

You can pass variables from You can even run tasks inside a WebWorker, taskorama is available in the worker scope :

const url = 'https://jsonplaceholder.typicode.com/photos'

const workerTask = Task.runInWorker(
  done => {
    // 'taskorama' is available in the worker!
    taskorama.fetch(url)
      .map(res => res.json())
      .map(json => ({ action: 'UPDATE_PHOTO_LIST', payload: json }))
      .run(result => {
        // call 'done()' to terminate the worker and send a message to the main thread
        done(result)
      })
  },
  { url: url, duration: 1000 } // passing two variables to the worker
)

workerTask.fork(console.error, console.log)
// logs : { action: 'UPDATE_PHOTO_LIST', payload: ... }

Task.wait

Creates a task that completes after a certain duration (first argument). It resolves with the value passed as second argument.

const timeoutTask = Task.wait(10000, "I'm done !")
const execTimeout = timeoutTask.fork(console.error, console.log)
// logs: "I'm done !" - after 10s

It can be cancelled like this :

execTimeout.cancel()
// the timeout is cancelled.

Task.all(array)

Creates a task that completes when all the tasks in the array are completed. It resolves with an array containing each value of each task of the array. If any of them rejects, the returned task rejects with the rejection reason.

If it is cancelled, it cancels all the tasks in the array as well.

const taskArray = [
  Task.wait(2000,`one`),
  Task.wait(3000,`two`),
  Task.wait(1000,`three`),
  Task.wait(4000,`four`),
]

const tasksAll = Task.all(taskArray)

tasksAll
  .fork(console.error, console.log)
// logs: ['one', 'two', 'three', 'four'] - after 4s

Task.race

Creates a task that is fulfilled or rejected as soon as a task in the array is fulfilled or rejected.

If it is cancelled, it cancels all the tasks in the array as well.

const taskArray = [
  Task.wait(2000,`one`),
  Task.wait(3000,`two`),
  Task.wait(1000,`three`),
  Task.wait(4000,`four`),
]

const tasksRace = Task.race(taskArray)

tasksRace
  .fork(console.error, console.log)
// logs: 'three' - after 1s

Task.sequence

Creates a task from an array of tasks, and run them in order. It resolves with an array containing the results of the execution of every task in the array in their initial order.

If it is cancelled, it cancels all the tasks in the array as well.

const taskArray = [
  Task.wait(2000,`one`),
  Task.wait(3000,`two`),
  Task.wait(1000,`three`)
]

const tasksSequence = Task.sequence(taskArray)

tasksSequence
  .fork(console.error, console.log)
// logs: ['one', 'two', 'three'] - after 6s

Task.parallel

Creates a task from an array of tasks, and run them concurrently. It resolves with an array containing the results of the execution of every task in the array in their order of completion.

If it is cancelled, it cancels all the tasks in the array as well.

const taskArray = [
  Task.wait(2000,`one`),
  Task.wait(3000,`two`),
  Task.wait(1000,`three`)
]

const tasksParallel = Task.parallel(taskArray)

tasksParallel
  .fork(console.error, console.log)
// logs: ['three', 'one', 'two'] - after 3s

Task.fromPromise

Creates a task from an existing Promise. Such a task cannot be cancelled because a Promise is not cancellable.

const p = Promise.resolve(2)
const taskFromPromise = Task.fromPromise(p)

taskFromPromise
  .fork(console.error, console.log)
// logs: 2

Task.flippedArgs

Creates a task where the Task description has its arguments flipped (like promises)

const task = Task.flippedArgs(function(resolve, reject) { 
  resolve(42)
})

task
  .fork(console.error, console.log)
// logs: 42

Task execution

When you execute a Task using .fork or .run, it returns a TaskExecution object which has the following methods :

.cancel()

Cancels the Task execution.

const afterSleep = () => console.log("I feel great!")
const sleep = Task.wait(1000)

const execution = sleep.run(afterSleep)

execution.cancel() 
// The task is cancelled and `afterSleep` is never called.

.inspect()

Inspects the execution of a Task (this method is synchronous)

Pending

const afterSleep = () => console.log("I feel great!")
const sleep = Task.wait(3000, 'Wake up!')

const execution = sleep.run(afterSleep)

setTimeout(() => {
  execution.inspect() // returns { status: 'pending', value: undefined }
}, 1000)

Cancelled

const afterSleep = () => console.log("I feel great!")
const sleep = Task.wait(1000)

const execution = sleep.run(afterSleep)

execution.cancel() 
execution.inspect() // returns { status: 'cancelled', value: undefined }

Resolved

const resolvedTask = Task.of('Done!')
const execution = resolvedTask(console.log, console.log)

execution.inspect() // returns { status: 'resolved', value: 'Done!' }

Rejected

const rejectedTask = Task.reject('Boo')
const execution = rejectedTask.fork(console.log, console.log)

execution.inspect() // returns { status: 'rejected', reason: 'Boo' }

😉