Socket
Socket
Sign inDemoInstall

fluture

Package Overview
Dependencies
Maintainers
1
Versions
109
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fluture - npm Package Compare versions

Comparing version 0.5.7 to 0.6.0-beta1

265

fluture.js

@@ -23,2 +23,12 @@ /*global define FantasyLand inspectf*/

/////////////
// Helpers //
/////////////
function noop(){}
function fork(m, rej, res){
const clean = m._f(rej, res);
return typeof clean === 'function' ? clean : noop;
}
///////////////////

@@ -44,2 +54,6 @@ // Type checking //

function isBoolean(b){
return typeof b === 'boolean';
}
////////////////////

@@ -90,4 +104,5 @@ // Error handling //

function check$Future(fork){
if(!isFunction(fork)) error$invalidArgument('Future', 0, 'be a function', fork);
function check$Future(f, b){
if(!isFunction(f)) error$invalidArgument('Future', 0, 'be a function', f);
if(!isBoolean(b)) error$invalidArgument('Future', 0, 'be a boolean', b);
}

@@ -135,3 +150,2 @@

//Check resolution value of the Future on which #ap was called.
function check$ap$f(f){

@@ -173,8 +187,8 @@ if(!isFunction(f)) throw new TypeError(

function check$cache$settle(oldState, newState, oldValue, newValue){
if(oldState > 1) throw new Error(
'Future.cache expects the Future it wraps to only resolve or reject once; '
+ ' a cached Future tried to ' + (newState === 2 ? 'reject' : 'resolve') + ' a second time.'
if(oldState !== 'pending') throw new Error(
'A cached Future may only resolve or reject once;'
+ ` tried to go into a ${newState} state while already ${oldState}.`
+ ' Please check your cached Future and make sure it does not call res or rej multiple times'
+ '\n It was ' + (oldState === 2 ? 'rejected' : 'resolved') + ' with: ' + show(oldValue)
+ '\n It got ' + (newState === 2 ? 'rejected' : 'resolved') + ' with: ' + show(newValue)
+ `\n It was ${oldState} with: ${show(oldValue)}`
+ `\n It got ${newState} with: ${show(newValue)}`
);

@@ -215,14 +229,13 @@ }

//Constructor.
function FutureClass(f){
function FutureClass(f, b){
this._f = f;
this._b = b;
}
//A createFuture function which pretends to be Future.
function Future(f){
check$Future(f);
return new FutureClass(f);
function Future(f, b){
if(arguments.length < 2) b = true;
check$Future(f, b);
return new FutureClass(f, b);
}
//The of method.
function Future$of(x){

@@ -236,3 +249,13 @@ return new FutureClass(function Future$of$fork(rej, res){

check$fork(this, rej, res);
this._f(rej, res);
let immediate = false, clear;
const autoclear = this._b;
clear = fork(this, function Future$fork$rej(x){
rej(x);
autoclear && clear ? clear() : (immediate = true);
}, function Future$fork$res(x){
res(x);
autoclear && clear ? clear() : (immediate = true);
});
autoclear && immediate && clear();
return clear;
}

@@ -244,8 +267,17 @@

return new FutureClass(function Future$chain$fork(rej, res){
_this._f(rej, function Future$chain$res(x){
let cleared = false, clearThat = noop;
const clearThis = fork(_this, function Future$chain$rej(x){
cleared || rej(x);
}, function Future$chain$res(x){
if(cleared) return;
const m = f(x);
check$chain$f(m, f, x);
m._f(rej, res);
clearThat = fork(m, e => cleared || rej(e), x => cleared || res(x));
});
});
return function Future$chain$clear(){
cleared = true;
clearThis();
clearThat();
};
}, this._b);
}

@@ -257,8 +289,17 @@

return new FutureClass(function Future$chainRej$fork(rej, res){
_this._f(function Future$chainRej$rej(x){
let cleared = false, clearThat = noop;
const clearThis = fork(_this, function Future$chainRej$rej(x){
if(cleared) return;
const m = f(x);
check$chainRej$f(m, f, x);
m._f(rej, res);
}, res);
});
clearThat = fork(m, e => cleared || rej(e), x => cleared || res(x));
}, function Future$chainRej$res(x){
cleared || res(x);
});
return function Future$chainRej$clear(){
cleared = true;
clearThis();
clearThat();
};
}, _this._b);
}

@@ -270,6 +311,13 @@

return new FutureClass(function Future$map$fork(rej, res){
_this._f(rej, function Future$map$res(x){
res(f(x));
let cleared = false;
const clear = fork(_this, function Future$map$rej(x){
cleared || rej(x);
}, function Future$map$res(x){
cleared || res(f(x));
});
});
return function Future$map$clear(){
cleared = true;
clear();
};
}, _this._b);
}

@@ -281,5 +329,6 @@

return new FutureClass(function Future$ap$fork(g, res){
let _f, _x, ok1, ok2, ko;
const rej = x => ko || (ko = 1, g(x));
_this._f(rej, function Future$ap$resThis(f){
let _f, _x, ok1, ok2, ko, cleared = false;
const rej = x => cleared || ko || (ko = 1, g(x));
const clearThis = fork(_this, rej, function Future$ap$resThis(f){
if(cleared) return;
if(!ok2) return void (ok1 = 1, _f = f);

@@ -289,3 +338,4 @@ check$ap$f(f);

});
m._f(rej, function Future$ap$resThat(x){
const clearThat = fork(m, rej, function Future$ap$resThat(x){
if(cleared) return;
if(!ok1) return void (ok2 = 1, _x = x)

@@ -295,3 +345,8 @@ check$ap$f(_f);

});
});
return function Future$ap$clear(){
cleared = true;
clearThis();
clearThat();
};
}, _this._b);
}

@@ -307,7 +362,12 @@

return new FutureClass(function Future$race$fork(rej, res){
let settled = false;
const once = f => a => settled || (settled = true, f(a));
_this._f(once(rej), once(res));
m._f(once(rej), once(res));
});
let settled = false, cleared = false;
const once = f => a => cleared || settled || (settled = true, f(a));
const clearThis = fork(_this, once(rej), once(res));
const clearThat = fork(m, once(rej), once(res));
return function Future$race$clear(){
cleared = true;
clearThis();
clearThat();
};
}, _this._b);
}

@@ -319,12 +379,17 @@

return new FutureClass(function Future$or$fork(rej, res){
let ok = false, ko = false, val, err;
_this._f(
() => ko ? rej(err) : ok ? res(val) : (ko = true),
x => (ok = true, res(x))
let ok = false, ko = false, val, err, cleared = false;
const clearThis = fork(_this,
() => cleared || ko ? rej(err) : ok ? res(val) : (ko = true),
x => cleared || (ok = true, res(x))
);
m._f(
e => ok || (ko ? rej(e) : (err = e, ko = true)),
x => ok || (ko ? res(x) : (val = x, ok = true))
const clearThat = fork(m,
e => cleared || ok || (ko ? rej(e) : (err = e, ko = true)),
x => cleared || ok || (ko ? res(x) : (val = x, ok = true))
);
});
return function Future$or$clear(){
cleared = true;
clearThis();
clearThat();
};
}, _this._b);
}

@@ -336,4 +401,13 @@

return new FutureClass(function Future$fold$fork(rej, res){
_this._f(e => res(f(e)), x => res(g(x)));
});
let cleared = false;
const clear = fork(_this, function Future$fold$rej(e){
cleared || res(f(e));
}, function Future$fold$res(x){
cleared || res(g(x));
});
return function Future$fold$clear(){
cleared = true;
clear();
};
}, _this._b);
}

@@ -343,3 +417,3 @@

check$value(this, f);
this._f(
return this.fork(
function Future$value$rej(e){

@@ -365,5 +439,5 @@ throw new Error(

const _this = this;
let que = [];
let value, state;
let que = [], value, state = 'idle';
const settleWith = newState => function Future$cache$settle(newValue){
if(state === 'idle') return;
check$cache$settle(state, newState, value, newValue);

@@ -378,12 +452,19 @@ value = newValue; state = newState;

return new FutureClass(function Future$cache$fork(rej, res){
let clear = noop;
switch(state){
case 1: que.push({2: rej, 3: res}); break;
case 2: rej(value); break;
case 3: res(value); break;
default:
state = 1;
que.push({2: rej, 3: res});
_this.fork(settleWith(2), settleWith(3));
case 'pending': que.push({rejected: rej, resolved: res}); break;
case 'rejected': rej(value); break;
case 'resolved': res(value); break;
case 'idle':
state = 'pending';
que.push({rejected: rej, resolved: res});
clear = fork(_this, settleWith('rejected'), settleWith('resolved'));
}
});
return function Future$cache$clear(){
state = 'idle';
value = undefined;
que = [];
clear();
};
}, false);
}

@@ -451,39 +532,19 @@

//chain :: Chain m => (a -> m b) -> m a -> m b
Future.chain = createUnaryDispatcher('chain');
//chainRej :: (a -> Future a c) -> Future a b -> Future a c
Future.chainRej = createUnaryDispatcher('chainRej');
//map :: Functor m => (a -> b) -> m a -> m b
Future.map = createUnaryDispatcher('map');
//ap :: Apply m => m (a -> b) -> m a -> m b
Future.ap = function dispatch$ap(m, a){
if(arguments.length === 1) return a => dispatch$ap(m, a);
if(m && typeof m.ap === 'function') return m.ap(a);
error$invalidArgument('Future.ap', 0, 'have a "ap" method', m);
};
//fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void
Future.fork = createBinaryDispatcher('fork');
//race :: Future a b -> Future a b -> Future a b
Future.race = createUnaryDispatcher('race');
//or :: Future a b -> Future a b -> Future a b
Future.or = createUnaryDispatcher('or');
//fold :: (a -> c) -> (b -> c) -> Future a b -> Future _ c
Future.fold = createBinaryDispatcher('fold');
//value :: (b -> Void) -> Future a b -> Void
Future.value = createUnaryDispatcher('value');
//promise :: Future a b -> Promise b a
Future.promise = createNullaryDispatcher('promise');
//cache :: Future a b -> Future a b
Future.cache = createNullaryDispatcher('cache');
Future.ap = function dispatch$ap(m, a){
if(arguments.length === 1) return a => dispatch$ap(m, a);
if(m && typeof m.ap === 'function') return m.ap(a);
error$invalidArgument('Future.ap', 0, 'have a "ap" method', m);
};
//////////////////

@@ -493,3 +554,2 @@ // Constructors //

//Create a Future which rejects witth the given value.
Future.reject = function Future$reject(x){

@@ -501,3 +561,2 @@ return new FutureClass(function Future$reject$fork(rej){

//Create a Future which resolves after the given time with the given value.
Future.after = function Future$after(n, x){

@@ -507,3 +566,6 @@ if(arguments.length === 1) return x => Future$after(n, x);

return new FutureClass(function Future$after$fork(rej, res){
setTimeout(res, n, x);
const id = setTimeout(res, n, x);
return function Future$after$clear(){
clearTimeout(id);
};
})

@@ -513,6 +575,6 @@ };

Future.cast = function Future$cast(m){
check$cast(m);
if(m instanceof FutureClass){
return m;
}
check$cast(m);
return new FutureClass(function Future$cast$fork(rej, res){

@@ -523,3 +585,2 @@ m.fork(rej, res);

//encase :: (a -> !b | c) -> a -> Future b c
Future.encase = function Future$encase(f, x){

@@ -540,4 +601,2 @@ if(arguments.length === 1) return x => Future$encase(f, x);

//Create a Future which resolves with the return value of the given function,
//or rejects with the exception thrown by the given function.
Future.try = function Future$try(f){

@@ -547,3 +606,2 @@ return Future.encase(f, undefined);

//node :: ((err, a) -> Void) -> Future[Error, a]
Future.node = function Future$node(f){

@@ -556,3 +614,2 @@ check$node(f);

//parallel :: PositiveInteger -> [Future a b] -> Future a [b]
Future.parallel = function Future$parallel(i, ms){

@@ -563,11 +620,17 @@ if(arguments.length === 1) return ms => Future$parallel(i, ms);

return l < 1 ? Future$of([]) : new FutureClass(function Future$parallel$fork(rej, res){
let ko = false;
let ok = 0;
const out = new Array(l);
const next = j => i < l ? fork(ms[i], i++) : (j === l && res(out));
const fork = (m, j) => (check$parallel$m(m, j), m._f(
e => ko || (rej(e), ko = true),
x => ko || (out[j] = x, next(++ok))
));
ms.slice(0, i).forEach(fork);
let ko = false, ok = 0, cleared = false;
const clears = [], out = new Array(l);
const next = j => i < l ? run(ms[i], i++) : (j === l && res(out));
const run = (m, j) => {
check$parallel$m(m, j);
clears.push(fork(m,
e => cleared || ko || (rej(e), ko = true),
x => cleared || ko || (out[j] = x, next(++ok))
));
}
ms.slice(0, i).forEach(run);
return function Future$parallel$clear(){
cleared = true;
clears.forEach(f => f());
};
});

@@ -574,0 +637,0 @@ };

{
"name": "fluture",
"version": "0.5.7",
"version": "0.6.0-beta1",
"description": "A mathematically correct alternative to Promises for asynchronous control flow",

@@ -15,5 +15,6 @@ "main": "fluture.js",

"setup": "npm run post-merge && cp scripts/hooks/* .git/hooks && git config push.followTags true",
"test": "npm run check-version && npm run clean && npm run lint && npm run test:unit",
"test": "npm run check-version && npm run clean && npm run lint && npm run test:coverage",
"test:opt": "node --allow-natives-syntax --trace-opt --trace-deopt --trace-inlining scripts/test-opt",
"test:unit": "node --harmony-destructuring node_modules/.bin/istanbul cover --report html ./node_modules/.bin/_mocha -- --ui bdd --reporter spec --check-leaks --full-trace && codecov"
"test:unit": "node --harmony-destructuring ./node_modules/.bin/_mocha --ui bdd --reporter spec --check-leaks --full-trace",
"test:coverage": "node --harmony-destructuring node_modules/.bin/istanbul cover --report html ./node_modules/.bin/_mocha -- --ui bdd --reporter dot --bail --check-leaks && codecov"
},

@@ -20,0 +21,0 @@ "author": "Aldwin Vlasblom <aldwin.vlasblom@gmail.com> (https://github.com/Avaq)",

@@ -8,3 +8,3 @@ # Fluture

[![Build Status](https://travis-ci.org/Avaq/Fluture.svg?branch=master)](https://travis-ci.org/Avaq/Fluture)
[![Code Coverage](https://codecov.io/github/Avaq/Fluture/coverage.svg?branch=develop)](https://codecov.io/github/Avaq/Fluture/fluture.js?branch=develop)
[![Code Coverage](https://codecov.io/github/Avaq/Fluture/coverage.svg?branch=master)](https://codecov.io/github/Avaq/Fluture/fluture.js?branch=master)

@@ -19,3 +19,16 @@ Futures are containers which represent some eventual value as a result of an

## Table of contents
- [Usage](#usage)
- [Motivation and Features](#motivation-and-features)
- [Documentation](#documentation)
- [Type signatures](#type-signatures)
- [Constructors](#constructors)
- [Method API](#method-api)
- [Dispatcher API](#dispatcher-api)
- [Cancellation and resource disposal](#cancellation-and-resource-disposal)
- [Futurization](#futurization)
- [Benchmarks](#benchmarks)
- [The name](#the-name)
## Usage

@@ -51,11 +64,17 @@

## Motivation
## Motivation and Features
Existing implementations of Future are a pain to debug. This library was made in
an effort to provide **great error messages** when something goes wrong. The
library also comes bundled with many **async control utilities**. To prevent
these features from coming at the cost of performance, Fluture was optimized to
operate at **high performance**. For an overview of differences between Fluture
and other Future implementations, look at [this wiki article][15].
an effort to provide **great error messages** when something goes wrong. Some
other features include:
* Plenty of async control utilities, like
[`Future.parallel`](#parallel--positiveinteger---future-a-b---future-a-b)
and [`Future#or`](#or--future-a-b--future-a-b---future-a-b).
* [Process cancellation and automatic resource disposal](#cancellation-and-resource-disposal).
* High performance.
For an overview of differences between Fluture and other Future implementations,
have a look at [this wiki article][15].
## Documentation

@@ -81,3 +100,3 @@

#### `Future :: ((a -> Void), (b -> Void) -> Void) -> Future a b`
#### `Future :: ((a -> ()), (b -> ()) -> ?(() -> ())) -> Future a b`

@@ -144,3 +163,3 @@ A (monadic) container which represents an eventual value. A lot like Promise but

#### `try :: (Void -> !a | b) -> Future a b`
#### `try :: (() -> !a | b) -> Future a b`

@@ -159,3 +178,3 @@ A constructor that creates a Future which resolves with the result of calling

#### `node :: ((a, b -> Void) -> Void) -> Future a b`
#### `node :: ((a, b -> ()) -> ()) -> Future a b`

@@ -218,27 +237,5 @@ A constructor that creates a Future which rejects with the first argument given

#### `cache :: Future a b -> Future a b`
Returns a Future which caches the resolution value of the given Future so that
whenever it's forked, it can load the value from cache rather than reexecuting
the chain.
```js
const eventualPackage = Future.cache(
Future.node(done => {
console.log('Reading some big data');
fs.readFile('package.json', 'utf8', done)
})
);
eventualPackage.fork(console.error, console.log);
//> "Reading some big data"
//> "{...}"
eventualPackage.fork(console.error, console.log);
//> "{...}"
```
### Method API
#### `fork :: Future a b ~> (a -> Void), (b -> Void) -> Void`
#### `fork :: Future a b ~> (a -> ()), (b -> ()) -> () -> ()`

@@ -371,4 +368,32 @@ Execute the Future (which up until now was merely a container for its

#### `value :: Future a b ~> (b -> Void) -> Void`
#### `cache :: Future a b ~> Future a b`
Returns a cached version of the Future so that whenever it's forked, it can load
the value from cache rather than reexecuting the chain. This means you can use
the same Future in multiple `chain`s, without having to worry that it's going
to re-execute the computation every time.
Please note that cached Futures, and Futures derived from them do not
automatically [dispose of resources](#automatic-resource-disposal). When the
cached Future is [cancelled or disposed manually](#manual-resource-disposal-and-cancellation),
it will clear its internal cache. The next time it's forked *after* that, it
must re-execute the underlying Future to populate its cache again.
```js
const eventualPackage = Future.node(done => {
console.log('Reading some big data');
fs.readFile('package.json', 'utf8', done)
})
.cache();
eventualPackage.fork(console.error, console.log);
//> "Reading some big data"
//> "{...}"
eventualPackage.fork(console.error, console.log);
//> "{...}"
```
#### `value :: Future a b ~> (b -> ()) -> () -> ()`
Extracts the value from a resolved Future by forking it. Only use this function

@@ -400,3 +425,3 @@ if you are sure the Future is going to be resolved, for example; after using

#### `fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void`
#### `fork :: (a -> ()) -> (b -> ()) -> Future a b -> () -> ()`

@@ -406,4 +431,4 @@ Dispatches the first and second arguments to the `fork` method of the third argument.

```js
const consoleFork = Future.fork(console.error, console.log);
consoleFork(Future.of('Hello'));
const consoleFork = fork(console.error, console.log);
consoleFork(of('Hello'));
//> "Hello"

@@ -436,6 +461,6 @@ ```

```js
const first = futures => futures.reduce(Future.race);
const first = futures => futures.reduce(race);
first([
Future.after(100, 'hello'),
Future.after(50, 'bye'),
after(100, 'hello'),
after(50, 'bye'),
Future(rej => setTimeout(rej, 25, 'nope'))

@@ -452,19 +477,10 @@ ])

```js
const any = futures => futures.reduce(Future.or, Future.reject('Empty list!'));
const program = S.pipe([
reject,
or(of('second chance')),
value(console.log)
]);
any([
Future.reject('first: nope'),
Future.of('second: yep'),
Future.reject('third: yep')
])
.fork(console.error, console.log);
//> "second: yep"
any([
Future.reject('first: nope'),
Future.reject('second: nope'),
Future.reject('third: nope')
])
.fork(console.error, console.log);
//> "third: nope"
program('first chance')
> "second chance"
```

@@ -476,6 +492,93 @@

#### `value :: (b -> Void) -> Future a b -> Void`
#### `cache :: Future a b -> Future a b`
Dispatches to the `cache` method.
```js
const cachedConnection = Future.cache(mysqlConnect());
```
#### `value :: (b -> ()) -> Future a b -> () -> ()`
Dispatches the first argument to the `value` method of the second argument.
#### `promise :: Future a b -> Promise b a`
Dispatches to the `promise` method.
```js
Future.promise(Future.after(300, 'Hello')).then(console.log);
//> "Hello"
```
### Cancellation and resource disposal
#### Automatic resource disposal
When a Future is created, it is given the `fork` function. This `fork` function
sometimes creates resources, like `setTimeout`s in the event loop or database
connections. In order to deal with the disposal of these resources, one may
*return* a function from `fork`, which will be automatically called after the
Future has forked. This function is expected to be idempotent.
It's the responsibility of this `fork` function to prevent `rej` or `res` from
being called after its returned disposal function has been called. All internal
Fluture functions, for example `Future.after`, play by these rules.
```js
const createDatabaseConnection = settings => Future((rej, res) => {
const conn = mysql.connect(settings, res);
return () => conn.hasEnded || conn.end();
});
createDatabaseConnection()
.chain(conn => conn.query('SELECT 1 + 1 AS two'))
//When we `fork`, all of the resource disposers will be automatically called.
.fork(console.error, console.log);
```
If you don't want a particular Future to automatically dispose of its resources,
you can construct it with `false` passed as its second argument:
```js
Future(
rej => {
const id = setTimeout(rej, 2000, 'timed out')
return () => clearTimeout(id);
},
false //<---
)
```
This Future, and any Future's derived from it through `map`, `chain`, etc. will
no longer automatically dispose of their resources after being forked. This
allows resources to only be disposed manually.
#### Manual resource disposal and cancellation
Both `.fork()` and `.value()` return the disposal function and you can call it
at any time to manually dispose of resources.
Besides resource disposal, this function can also be used to cancel running
Futures. When called prematurely it will dispose the resources and cause the
whole pipeline to come to a halt:
```js
const loadPage = url => Future((rej, res) => {
const req = new XMLHttpRequest();
req.addEventListener('load', res);
req.addEventListener('error', rej);
req.open('GET', url);
req.send();
return () => (req.readyState < 4) && req.abort();
});
const cancel = loadPage('https://github.com').fork(onFailure, onSuccess);
//Cancel the Future immediately. Nothing will happen; `onFailure` nor
//`onSuccess` will ever be called anymore because `cancel` called `req.abort()`.
cancel();
```
### Futurization

@@ -482,0 +585,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc