rpominov / fun-task

Abstraction for managing asynchronous code in JS
MIT License
373 stars 18 forks source link
async fp functional-programming future monad promise task

fun-task* Build Status Coverage Status

An abstraction for managing asynchronous code in JS.

* The name is an abbreviation for "functional task" (this library is based on many ideas from Functional Programming). The type that library implements is usually referred to in the documentation as just "Task".

Installation

NPM

npm install fun-task
// modern JavaScript
import Task from 'fun-task'

// classic JavaScript
var Task = require('fun-task')

CDN

<script src="https://unpkg.com/fun-task/umd/funTask.js"></script>
<script>
  var Task = window.FunTask
</script>

What is a Task?

Task is an abstraction similar to Promises. The key difference is that a Task represents a computation while a Promise represents only a result of a computation. If we have a Task we can: start the computation; terminate it before it's finished; or wait until it finishes, and get the result. While with a Promise we can only get the result. This difference doesn't make Tasks better, they are just different, we can find legitimate use cases for both abstractions. Let's review it again:

If we have a Task:

If we have a Promise:

The last item is important. This might be an advantage of Promises over Tasks. If two consumers have a same Task, each of them have to spawn their own instance of the computation in order to get the result, and they may even get different results.

What is a computation?

function computation(onSuccess, onFailure) {
  // ...
  return () => {
    // ... cancellation logic
  }
}

From Task API perspective, computation is a function that accepts two callbacks. It should call one of them after completion with the final result. Also a computation may return a function with cancellation logic, or it can return undefined if particular computation has no cancellation logic.

Creating a Task from a computation is easy, we just call task = Task.create(computation). This is very similar to new Promise(computation), but Task won't execute computation immediately, the computation starts only when task.run() is called.

Documentation

Flow

The NPM package ships with Flow definitions. So you can do something like this if you use Flow:

// @flow

import Task from 'fun-task'

function incrementTask<F>(task: Task<number, F>): Task<number, F> {
  return task.map(x => x + 1)
}

Specifications compatibility

Task is compatible with Fantasy Land and Static Land implementing:

Development

npm run lobot -- --help

Run lobot commands as npm run lobot -- args...