Comparing version 0.1.0 to 0.1.1
@@ -1,33 +0,35 @@ | ||
(function() { | ||
'use strict'; | ||
var flyd = require('flyd'); | ||
var stream = flyd.stream; | ||
var filter = require('flyd-filter'); | ||
var lift = require('flyd-lift'); | ||
var inLast = require('flyd-inlast'); | ||
var stream = flyd.stream; | ||
var magicSeq = 'abbaba'; | ||
var seqLen = magicSeq.length; | ||
var maxTime = 5000; | ||
var magicSeq = 'abbaba'; | ||
var setMsg = function(msg) { message.innerHTML = msg; }; | ||
var setMsg = function(msg) { message.innerHTML = msg; }; | ||
document.addEventListener('DOMContentLoaded', function() { | ||
var clicks = stream(); | ||
btnA.addEventListener('click', clicks.bind(null, 'a')); | ||
btnB.addEventListener('click', clicks.bind(null, 'b')); | ||
document.addEventListener('DOMContentLoaded', function() { | ||
var click = stream(); | ||
btnA.addEventListener('click', click.bind(null, 'a')); | ||
btnB.addEventListener('click', click.bind(null, 'b')); | ||
var corrects = flyd.reduce(function(cs, c) { | ||
var l = cs.length, correct = (c === magicSeq[l]); | ||
console.log(l, correct); | ||
return !correct && l > 0 ? [] | ||
: !correct && l === 0 ? [] | ||
: l + 1 < magicSeq.length ? cs.concat(c) | ||
: (setMsg('Combination unlocked!'), []); | ||
}, [], click); | ||
var scheduled = flyd.map(function(cor) { | ||
if (cor.length === 1) return setTimeout(function() { | ||
setMsg('You\'re not fast enough, try again'); | ||
corrects([]); | ||
}, 5000); | ||
}, corrects); | ||
flyd.map(function(c) { console.log(c); }, corrects); | ||
stream([corrects], function() { | ||
if (corrects().length === 0 && scheduled.val) clearTimeout(scheduled.val); | ||
}); | ||
}); | ||
})(); | ||
var correctClicks = flyd.reduce(function(n, c) { | ||
return magicSeq[n] === c ? n + 1 | ||
: magicSeq[0] === c ? 1 | ||
: 0; | ||
}, 0, clicks); | ||
var clicksInLast5s = inLast(maxTime, clicks); | ||
lift(function(corrects, inLast5s) { | ||
var complete = corrects === seqLen, inTime = inLast5s.length >= seqLen; | ||
setMsg(complete && inTime ? 'Combination unlocked' | ||
: complete && !inTime ? "You're not fast enough, try again!" | ||
: corrects); | ||
}, correctClicks, clicksInLast5s); | ||
flyd.map(function(c) { console.log('cor', c); }, correctClicks); | ||
flyd.map(function(c) { console.log('lst', c); }, clicksInLast5s); | ||
}); |
95
flyd.js
@@ -21,16 +21,5 @@ (function (root, factory) { | ||
// Globals | ||
var queue = []; | ||
var isFlushingQueue = false; | ||
var toUpdate = []; | ||
var inStream; | ||
function flushQueue() { | ||
if (isFlushingQueue) return; | ||
isFlushingQueue = true; | ||
for (var s; s = queue.shift();) { | ||
s.inQueue = false; | ||
s.update(); | ||
} | ||
isFlushingQueue = false; | ||
} | ||
function removeListener(listeners, s) { | ||
@@ -46,3 +35,3 @@ var idx = listeners.indexOf(s); | ||
var reduce = curryN(3, function(f, acc, s) { | ||
var scan = curryN(3, function(f, acc, s) { | ||
var ns = stream([s], function() { | ||
@@ -68,7 +57,7 @@ return (acc = f(acc, s())); | ||
var s1 = this; | ||
return stream([s1, s2], function() { return s1()(s2()); }, true); | ||
return stream([s1, s2], function() { return s1()(s2()); }); | ||
} | ||
function of(v) { | ||
return stream()(v); | ||
return stream(v); | ||
} | ||
@@ -85,8 +74,43 @@ | ||
function updateStream() { | ||
if (initialDepsNotMet(this)) return; | ||
var returnVal = this.fn(this, this.depChanged); | ||
if (returnVal !== undefined) this(returnVal); | ||
function updateStream(s) { | ||
if (initialDepsNotMet(s)) return; | ||
inStream = s; | ||
var returnVal = s.fn(s, s.depChanged); | ||
if (returnVal !== undefined) { | ||
s(returnVal); | ||
} | ||
inStream = undefined; | ||
s.depChanged = undefined; | ||
} | ||
function findDeps(order, s) { | ||
if (!s.queued) { | ||
s.queued = true; | ||
for (var i = 0; i < s.listeners.length; ++i) { | ||
findDeps(order, s.listeners[i]); | ||
} | ||
order.push(s); | ||
} | ||
} | ||
function updateDeps(s) { | ||
var i, order = []; | ||
for (i = 0; i < s.listeners.length; ++i) { | ||
s.listeners[i].depChanged = s; | ||
findDeps(order, s.listeners[i]); | ||
} | ||
for (i = order.length - 1; i >= 0; --i) { | ||
if (!isUndefined(order[i].depChanged)) { | ||
updateStream(order[i]); | ||
} | ||
order[i].queued = false; | ||
} | ||
} | ||
function flushUpdate() { | ||
for (var s; s = toUpdate.shift();) { | ||
updateDeps(s); | ||
} | ||
} | ||
function destroy(stream) { | ||
@@ -110,3 +134,3 @@ if (stream.listeners.length !== 0) { | ||
if (arguments.length > 0) { | ||
if (!isUndefined(n) && n !== null && isFunction(n.then)) { | ||
if (n && isFunction(n.then)) { | ||
n.then(s); | ||
@@ -117,10 +141,10 @@ return; | ||
s.hasVal = true; | ||
s.listeners.forEach(function(st) { | ||
st.depChanged = s; | ||
if (!st.inQueue) { | ||
st.inQueue = true; | ||
queue.push(st); | ||
if (inStream !== s) { | ||
toUpdate.push(s); | ||
if (!inStream) flushUpdate(); | ||
} else { | ||
for (var j = 0; j < s.listeners.length; ++j) { | ||
s.listeners[j].depChanged = s; | ||
} | ||
}); | ||
flushQueue(); | ||
} | ||
return s; | ||
@@ -135,5 +159,5 @@ } else { | ||
s.deps = []; | ||
s.depsMet = isUndefined(waitForDeps) ? false : true; | ||
s.depsMet = isUndefined(waitForDeps) && arguments.length > 1 ? false : true; | ||
s.depChanged = undefined; | ||
s.inQueue = true; | ||
s.queued = false; | ||
s.fn = fn; | ||
@@ -147,3 +171,2 @@ | ||
if (arguments.length > 1) { | ||
s.update = updateStream; | ||
s.deps = arg; | ||
@@ -153,7 +176,6 @@ arg.forEach(function(dep) { | ||
}); | ||
queue.push(s); | ||
flushQueue(); | ||
updateStream(s); | ||
flushUpdate(); | ||
} else if (arguments.length === 1) { | ||
s.val = arg; | ||
s.hasVal = true; | ||
s(arg); | ||
} | ||
@@ -291,3 +313,4 @@ return s; | ||
merge: merge, | ||
reduce: reduce, | ||
reduce: scan, // Legacy | ||
scan: scan, | ||
destroy: destroy, | ||
@@ -294,0 +317,0 @@ map: curryN(2, function(f, s) { return map(s, f); }), |
{ | ||
"name": "flyd", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "The less is more, modular, functional reactive programming library", | ||
@@ -5,0 +5,0 @@ "main": "flyd.js", |
322
README.md
@@ -14,2 +14,3 @@ [![Build Status](https://travis-ci.org/paldepind/flyd.svg?branch=master)](https://travis-ci.org/paldepind/flyd) | ||
* [Modules](#modules) | ||
* [Misc](#misc) | ||
@@ -32,10 +33,10 @@ ## Introduction | ||
Instead of methods it gives you curried functions with arguments in the | ||
correct order for partial aplication. This increases the expressive power and | ||
correct order for partial application. This increases the expressive power and | ||
the extensibility of the library. | ||
* Supports the transducer protocol. You can for instance transduce streams with | ||
([Ramda](http://ramdajs.com/). | ||
[Ramda](http://ramdajs.com/). | ||
* Complies to the [fantasy land](https://github.com/fantasyland/fantasy-land) | ||
applicative specification. | ||
* Elegant support for promises. | ||
* Atomic updates | ||
* [Atomic updates](#atomic-updates) | ||
* Easy to extend with custom [modules](#modules) | ||
@@ -46,7 +47,8 @@ | ||
* [Sum](http://paldepind.github.io/flyd/examples/sum/) - very simple example | ||
* [Multiple clicks](http://paldepind.github.io/flyd/examples/multiple-clicks/) | ||
- a remake of the multiple clicks example from "The introduction to | ||
Reactive Programming you've been missing". Compare it to the [Rx | ||
implementation](http://jsfiddle.net/staltz/4gGgs/27/) not quite as elegant. | ||
* [Multiple clicks](http://paldepind.github.io/flyd/examples/multiple-clicks/) - a remake | ||
of the multiple clicks example from "The introduction to Reactive | ||
Programming you've been missing". Compare it to the not quite as elegant [Rx | ||
implementation](http://jsfiddle.net/staltz/4gGgs/27/). | ||
* [Secret combination](http://paldepind.github.io/flyd/examples/secret-combination/) | ||
* [Ramda transducer](https://github.com/paldepind/flyd/tree/master/examples/ramda-transducer) | ||
@@ -57,2 +59,11 @@ For other examples check the source code of the [modules](#modules). | ||
This is not general tutorial to functional reactive programming. For that take | ||
a look at [The introduction to Reactive Programming you've been | ||
missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) and/or [this Elm | ||
tutorial](http://elm-lang.org/learn/Using-Signals.elm) if you are comfortable | ||
with reading Haskell-like code. | ||
This tutorial will introduce you to the core of Flyd and show how to use it to | ||
build FRP abstractions. | ||
### Creating streams | ||
@@ -62,13 +73,13 @@ | ||
The function `stream` creates a representation of a value that changes over time. | ||
A stream is a function and at first sight it works a bit like a getter-setter: | ||
A stream is a function. At first sight it works a bit like a getter-setter: | ||
```javascript | ||
// Create a stream with initial value 5. | ||
var number = stream(5); | ||
var number = flyd.stream(5); | ||
// Get the current value of the stream. | ||
number(); // returns 5 | ||
console.log(number()); // logs 5 | ||
// Update the value of the stream. | ||
number(7); // returns 7 | ||
console.log(number(7)); // logs 7 | ||
// The stream now returns the new value. | ||
number(); // returns 7 | ||
console.log(number()); // logs 7 | ||
``` | ||
@@ -83,5 +94,5 @@ | ||
```javascript | ||
var clicks = stream(); | ||
var clicks = flyd.stream(); | ||
document.getElementById('button').addEventListener('click', clicks); | ||
var messages = stream(); | ||
var messages = flyd.stream(); | ||
webSocket.onmessage = messages; | ||
@@ -97,8 +108,8 @@ ``` | ||
as in the above examples we can pass it a list of dependencies and a function. | ||
The function should calculate a value based on its dependencies which results | ||
in a new stream. Flyd automatically updates the stream whenever a dependency | ||
changes. | ||
The function should produce a value based on its dependencies. This new value | ||
results in a new stream. | ||
This means that the `sum` function below will be called whenever `x` and `y` changes. | ||
You can think of dependent stream as streams that automatically | ||
Flyd automatically updates the stream whenever a dependency changes. This | ||
means that the `sum` function below will be called whenever `x` and `y` | ||
changes. You can think of dependent stream as streams that automatically | ||
listens/subscribes to their dependencies. | ||
@@ -108,7 +119,7 @@ | ||
// Create two streams of numbers | ||
var x = stream(4); | ||
var y = stream(6); | ||
var x = flyd.stream(4); | ||
var y = flyd.stream(6); | ||
// Create a stream that depends on the two previous streams | ||
// and with its value given by the two added together. | ||
var sum = stream([x, y], function() { | ||
var sum = flyd.stream([x, y], function() { | ||
return x() + y(); | ||
@@ -118,5 +129,5 @@ }); | ||
x(12); | ||
sum(); // returns 18 | ||
console.log(sum()); // logs 18 | ||
y(8); | ||
sum(); // returns 20 | ||
console.log(sum()); // logs 20 | ||
``` | ||
@@ -128,13 +139,13 @@ | ||
// Create two streams of numbers | ||
var x = stream(4); | ||
var y = stream(6); | ||
var squareX = stream([x], function() { | ||
var x = flyd.stream(4); | ||
var y = flyd.stream(6); | ||
var squareX = flyd.stream([x], function() { | ||
return x() * x(); | ||
}); | ||
var squareXPlusY([y, doubleX], function() { | ||
return y() + doubleX(); | ||
var squareXPlusY = flyd.stream([y, squareX], function() { | ||
return y() + squareX(); | ||
}); | ||
squareXPlysY(); // returns 22 | ||
console.log(squareXPlusY()); // logs 22 | ||
x(2); | ||
squareXPlysY(); // returns 10 | ||
console.log(squareXPlusY()); // logs 10 | ||
``` | ||
@@ -147,5 +158,5 @@ | ||
// Create two streams of numbers | ||
var x = stream(1); | ||
var y = stream(2); | ||
var sum = stream([x, y], function(sum, changed) { | ||
var x = flyd.stream(1); | ||
var y = flyd.stream(2); | ||
var sum = flyd.stream([x, y], function(sum, changed) { | ||
// The stream can read from itself | ||
@@ -161,3 +172,3 @@ console.log('Last sum was ' + sum()); | ||
### Using calback APIs for asynchronous operations | ||
### Using callback APIs for asynchronous operations | ||
@@ -168,8 +179,8 @@ Instead of returning a value a stream can update itself by calling itself. This | ||
``` | ||
var urls = stream('/something.json'); | ||
var responses = stream([urls], function(resp) { | ||
var urls = flyd.stream('/something.json'); | ||
var responses = flyd.stream([urls], function(resp) { | ||
makeRequest(urls(), resp); | ||
}); | ||
stream([responses], function() { | ||
console.log('Recieved response!'); | ||
flyd.stream([responses], function() { | ||
console.log('Received response!'); | ||
console.log(responses()); | ||
@@ -179,3 +190,3 @@ }); | ||
Note that the stream above logging the responses from the server should only be called | ||
Note that the stream that logs the responses from the server should only be called | ||
after an actual response has been recieved (otherwise `responses()` whould return | ||
@@ -192,7 +203,7 @@ `undefined`). Fortunately a streams body will not be called before all of its declared | ||
```javascript | ||
var urls = stream('/something.json'); | ||
var responses = stream(function() { | ||
var urls = flyd.stream('/something.json'); | ||
var responses = flyd.stream(function() { | ||
return requestPromise(urls()); | ||
}); | ||
stream([responses], function() { | ||
flyd.stream([responses], function() { | ||
console.log('Recieved response!'); | ||
@@ -207,8 +218,8 @@ console.log(responses()); | ||
can do with it. Lets write a function that takes a stream and a function and | ||
returns a new stream with the functin applied to every value emitted by the | ||
returns a new stream with the function applied to every value emitted by the | ||
stream. In short, a `map` function. | ||
```javascript | ||
var mapStream = functin(f, s) { | ||
return stream([s], function() { | ||
var mapStream = function(f, s) { | ||
return flyd.stream([s], function() { | ||
return f(s()); | ||
@@ -220,14 +231,15 @@ }); | ||
We simply create a new stream dependent on the first stream. We declare | ||
the stream as a dependency so that our stream wont return values before | ||
the stream as a dependency so that our stream won't return values before | ||
the original stream produces its first value. | ||
Flyd includes a similair map function as part of its core. | ||
Flyd includes a similar map function as part of its core. | ||
### Reducing a stream | ||
Lets try something else: reducing a stream! It could look like this: | ||
Lets try something else: a scan function for accumulating a stream! It could | ||
look like this: | ||
```javascript | ||
var reduceStream = function(f, acc, s) { | ||
return stream([s], function() { | ||
var scanStream = function(f, acc, s) { | ||
return flyd.stream([s], function() { | ||
acc = f(acc, s()); | ||
@@ -239,23 +251,26 @@ return acc; | ||
Our reduce function takes a reducer function, in initial value and a stream. | ||
Every time the original stream emit a value we pass it to the reducer along | ||
with the accumulator. | ||
Our scan function takes a accumulator function, in initial value and a stream. | ||
Every time the original stream emit a value we pass it to the accumulator along | ||
with the accumulated value. | ||
Flyd includes a reduce function as part of its core. | ||
Flyd includes a scan function as part of its core. | ||
### Fin | ||
You're done! Now, check out the [API](#api) and/or the [examples](#examples). | ||
You're done! To learn more check out the [API](#api), the [examples](#examples) | ||
and the source of the [modules](#modules). | ||
## API | ||
### flyd.stream | ||
### flyd.stream(dependencies, body[, doesNotRequireDeps]) | ||
Creates a new stream. | ||
__Arguments__ | ||
* \[`dependencies`\] (array) – The streams on which this stream should initially depend. | ||
* `body` (function|\*) – The function body of the stream or it initial value. | ||
* \[`staticDependencies`\] – Disables automatic dependency resolution of the stream. | ||
__Signature__ | ||
* `dependencies` (array) – The streams on which this stream depends. | ||
* `body` (function) – The function body of the stream. | ||
* \[`doesNotRequireDeps`\] (boolean) – If `true` the function body can be | ||
invoked even before all dependencies have a value. | ||
__Returns__ | ||
@@ -267,12 +282,16 @@ | ||
Returns a new stream consisting of every value from `s` passed through `fn. I.e. `map` creates | ||
Returns a new stream consisting of every value from `s` passed through `fn`. I.e. `map` creates | ||
a new stream that listens to `s` and applies `fn` to every new value. | ||
__Signature__ | ||
`(a -> result) -> Stream a -> Stream result` | ||
__Example__ | ||
```javascript | ||
var numbers = stream(0); | ||
var numbers = flyd.stream(0); | ||
var squaredNumbers = flyd.map(function(n) { return n*n; }, numbers); | ||
``` | ||
###flyd.reduce(fn, acc, stream) | ||
###flyd.scan(fn, acc, stream) | ||
@@ -282,6 +301,10 @@ Creates a new stream with the results of calling the function on every incoming | ||
__Signature__ | ||
`(a -> b -> a) -> a -> Stream b -> Stream a` | ||
__Example__ | ||
```javascript | ||
var numbers = stream(); | ||
var sum = flyd.reduce(function(sum, n) { return sum+n; }, 0, numbers); | ||
var numbers = flyd.stream(); | ||
var sum = flyd.scan(function(sum, n) { return sum+n; }, 0, numbers); | ||
numbers(2)(3)(5); | ||
@@ -296,7 +319,11 @@ sum(); // 10 | ||
__Signature__ | ||
`Stream a -> Stream a - Stream a` | ||
__Example__ | ||
```javascript | ||
var btn1Clicks = stream(); | ||
var btn1Clicks = flyd.stream(); | ||
button1Elm.addEventListener(clicks); | ||
var btn2Clicks = stream(); | ||
var btn2Clicks = flyd.stream(); | ||
button2Elm.addEventListener(clicks); | ||
@@ -310,2 +337,6 @@ var allClicks = flyd.merge(btn1Clicks, btn2Clicks); | ||
__Signature__ | ||
`Transducer -> Stream a -> Stream b` | ||
__Example__ | ||
@@ -317,3 +348,3 @@ | ||
var results = []; | ||
var s1 = stream(); | ||
var s1 = flyd.stream(); | ||
var tx = t.compose( | ||
@@ -324,5 +355,5 @@ t.map(function(x) { return x * 2; }), | ||
var s2 = flyd.transduce(tx, s1); | ||
stream([s2], function() { results.push(s2()); }); | ||
flyd.stream([s2], function() { results.push(s2()); }); | ||
s1(1)(1)(2)(3)(3)(3)(4); | ||
result; // [2, 4, 6, 8] | ||
results; // [2, 4, 6, 8] | ||
``` | ||
@@ -336,2 +367,15 @@ | ||
__Signature__ | ||
`Stream -> undefined` | ||
__Example__ | ||
```javascript | ||
var s = flyd.map(function() { /* something */ }, someStream); | ||
flyd.destroy(s); | ||
s = undefined; | ||
// `s` can be garbage collected | ||
``` | ||
###flyd.curryN(n, fn) | ||
@@ -342,2 +386,14 @@ | ||
__Signature__ | ||
`Integer -> (* -> a) -> (* -> a)` | ||
__Example__ | ||
```javascript | ||
function add(x, y) { return x + y; }; | ||
flyd.curryN(2, add); | ||
var add | ||
``` | ||
###flyd.isStream(stream) | ||
@@ -347,2 +403,15 @@ | ||
__Signature__ | ||
`* -> Boolean` | ||
__Example__ | ||
```javascript | ||
var s = flyd.stream(1); | ||
var n = 1; | ||
flyd.isStream(s); //=> true | ||
flyd.isStream(n); //=> false | ||
``` | ||
###stream() | ||
@@ -352,8 +421,11 @@ | ||
__Signature__ | ||
`a` | ||
__Example__ | ||
```javascript | ||
var names = stream('Turing'); | ||
var names = flyd.stream('Turing'); | ||
names(); // 'Turing' | ||
names('Bohr'); | ||
names(); // 'Bohr' | ||
``` | ||
@@ -365,7 +437,32 @@ | ||
__Signature__ | ||
`a -> Stream a` | ||
__Example__ | ||
```javascript | ||
names('Bohr'); | ||
names(); // 'Bohr' | ||
``` | ||
###stream.map(f) | ||
Returns a new stream identical to the original exept every | ||
Returns a new stream identical to the original except every | ||
value will be passed through `f`. | ||
_Note:_ This function is included in order to support the fantasy land | ||
specification. | ||
__Signature__ | ||
Called bound to `Stream a`: `(a -> b) -> Stream b` | ||
__Example__ | ||
```javascript | ||
var numbers = flyd.stream(0); | ||
var squaredNumbers = numbers.map(function(n) { return n*n; }); | ||
``` | ||
###stream1.ap(stream2) | ||
@@ -378,13 +475,76 @@ | ||
_Note:_ This function is included in order to support the fantasy land | ||
specification. | ||
__Signature__ | ||
Called bound to `Stream (a -> b)`: `a -> Stream b` | ||
__Example__ | ||
```javascript | ||
var add = flyd.curryN(2, function(x, y) { return x + y; }); | ||
var numbers1 = flyd.stream(); | ||
var numbers2 = flyd.stream(); | ||
var addToNumbers1 = flyd.map(add, numbers1); | ||
var added = addToNumbers1.ap(numbers2); | ||
``` | ||
###stream.of(value) | ||
Returns a new stream with `value` as its initial value. | ||
Returns a new stream with `value` as its initial value. It is identical to | ||
calling `flyd.stream` with one argument. | ||
__Signature__ | ||
Called bound to `Stream (a)`: `b -> Stream b` | ||
__Example__ | ||
```javascript | ||
var n = flyd.stream(1); | ||
var m = n.of(1); | ||
``` | ||
### Modules | ||
* [flyd-filter](https://github.com/paldepind/flyd-filter) | ||
* [flyd-lift](https://github.com/paldepind/flyd-lift) | ||
* [flyd-flatmap](https://github.com/paldepind/flyd-flatmap) | ||
* [flyd-keepwhen](https://github.com/paldepind/flyd-keepwhen) | ||
* [flyd-sampleon](https://github.com/paldepind/flyd-sampleon) | ||
If you're created a module for Flyd open an issue or send a pull request and it | ||
will be added to this list. | ||
* [flyd-filter](https://github.com/paldepind/flyd-filter) – Filter values from stream based on predicate. | ||
* [flyd-lift](https://github.com/paldepind/flyd-lift) – Maps a function taking _n_ paramters over _n_ streams. | ||
* [flyd-flatmap](https://github.com/paldepind/flyd-flatmap) – Maps a function over a stream of streams and flattens the result to a single stream. | ||
* [flyd-keepwhen](https://github.com/paldepind/flyd-keepwhen) – Keep values from one stream only when another stream is true. | ||
* [flyd-obj](https://github.com/paldepind/flyd-obj) – Functions for working with stream in objects. | ||
* [flyd-sampleon](https://github.com/paldepind/flyd-sampleon) – Samples from a stream every time an event occurs on another stream. | ||
* [flyd-scanmerge](https://github.com/paldepind/flyd-scanmerge) – Merge and scan several streams into one. | ||
* Time related | ||
* [flyd-aftersilence](https://github.com/paldepind/flyd-aftersilence) – Buffers values from a source stream in an array and emits it after a specified duration of silience from the source stream. | ||
* [flyd-inlast](https://github.com/paldepind/flyd-inlast) - Creates a stream with emits a list of all values from the source stream that where emitted in a specified duration. | ||
## Misc | ||
### Atomic updates | ||
Consider code like the following | ||
```javascript | ||
var a = flyd.stream(1); | ||
var b = flyd.stream([a], function() { return a() * 2; }); | ||
var c = flyd.stream([a], function() { return a() + 4; }); | ||
var d = flyd.stream([b, c], function(self, ch) { | ||
result.push(b() + c()); | ||
}); | ||
``` | ||
Now, when a value flows down `a`, both `b` and `c` will change because they | ||
depend on `a`. If you merely consider streams as being events you'd expect `d` | ||
to be updated twice. Because `a` triggers `b` triggers `d` after which `a` also | ||
twiggers `c` which again triggers `d`. But Flyd will handle this better. | ||
Since only one value entered the system `d` will only be updated once with the | ||
changed values of `b` and `c`. This avoids superfluous updates of your streams. | ||
### Environment support | ||
Flyd should work in all JavaScript environments. Some of its modules may however | ||
assume ECMAScript 4. | ||
@@ -25,24 +25,32 @@ var assert = require('assert'); | ||
}); | ||
it('can set result by calling callback', function() { | ||
it('can set result by returning value', function() { | ||
var x = stream(3); | ||
var y = stream(4); | ||
var sum = stream([x, y], function(s) { | ||
s(x() + y()); | ||
var sum = stream([x, y], function() { | ||
return x() + y(); | ||
}); | ||
assert.equal(sum(), x() + y()); | ||
}); | ||
it('can set result by returning value', function() { | ||
it('is updated when dependencies change', function() { | ||
var x = stream(3); | ||
var y = stream(4); | ||
var sum = stream([x, y], function() { | ||
var sum = stream([x, y], function(s) { | ||
return x() + y(); | ||
}); | ||
assert.equal(sum(), x() + y()); | ||
assert.equal(sum(), x() + y()); // 7 | ||
x(12); | ||
assert.equal(sum(), x() + y()); // 16 | ||
y(8); | ||
assert.equal(sum(), x() + y()); // 20 | ||
}); | ||
it('is updated when dependencies change', function() { | ||
it('can set result by calling callback', function() { | ||
var x = stream(3); | ||
var y = stream(4); | ||
var times = 0; | ||
var sum = stream([x, y], function(s) { | ||
s(x() + y()); | ||
}); | ||
stream([sum], function() { | ||
times++; | ||
}); | ||
assert.equal(sum(), x() + y()); // 7 | ||
@@ -53,2 +61,3 @@ x(12); | ||
assert.equal(sum(), x() + y()); // 20 | ||
assert.equal(times, 3); | ||
}); | ||
@@ -170,7 +179,7 @@ it('can specify dependencies manually', function() { | ||
var y = stream(3); | ||
var doubleX = stream([x], function() { | ||
var doubleX = stream([x], function dx() { | ||
if (x() === 3) order.push(2); | ||
return x() * 2; | ||
}); | ||
var setAndY = stream([y], function() { | ||
var setAndY = stream([y], function sy() { | ||
x(3); | ||
@@ -226,2 +235,12 @@ order.push(1); | ||
}); | ||
it('can filter values', function() { | ||
var result = []; | ||
var n = stream(0); | ||
var lrg5 = stream([n], function() { | ||
if (n() > 5) return n(); | ||
}); | ||
flyd.map(function(v) { result.push(v); }, lrg5); | ||
n(4)(6)(2)(8)(3)(4); | ||
assert.deepEqual(result, [6, 8]); | ||
}); | ||
describe('promise integration', function() { | ||
@@ -296,3 +315,2 @@ it('pushes result of promise down the stream', function(done) { | ||
var sum = flyd.reduce(function(sum, n) { | ||
console.log(sum, n); | ||
return sum + n; | ||
@@ -389,2 +407,13 @@ }, 0, numbers); | ||
}); | ||
it('applies functions if streams have no initial value', function() { | ||
var result = []; | ||
var add = flyd.curryN(2, function(x, y) { return x + y; }); | ||
var numbers1 = stream(); | ||
var numbers2 = stream(); | ||
var addToNumbers1 = flyd.map(add, numbers1); | ||
var added = addToNumbers1.ap(numbers2); | ||
flyd.map(function (n) { result.push(n); }, added); | ||
numbers1(3); numbers2(2); numbers1(4); | ||
assert.deepEqual(result, [5, 6]); | ||
}); | ||
}); | ||
@@ -517,3 +546,27 @@ describe('of', function() { | ||
}); | ||
it('handles complex dependency graph', function() { | ||
var result = []; | ||
var a = flyd.stream(); | ||
var b = flyd.stream([a], function bs() { return a() + 1; }); | ||
var c = flyd.stream([a], function cs() { return a() + 2; }); | ||
var d = flyd.stream([c], function ds() { return c() + 3; }); | ||
var e = flyd.stream([b, d], function res(){ | ||
return b() + d(); | ||
}); | ||
flyd.map(function(v) { result.push(v); }, e); | ||
a(1)(5)(11); | ||
assert.deepEqual(result, [8, 16, 28]); | ||
}); | ||
it('handles another complex dependency graph', function() { | ||
var result = []; | ||
var a = flyd.stream(); | ||
var b = flyd.stream([a], function() { return a() + 1; }); | ||
var c = flyd.stream([a], function() { return a() + 2; }); | ||
var d = flyd.stream([a], function() { return a() + 4; }); | ||
var e = flyd.stream([b, c, d], function() { return b() + c() + d(); }); | ||
flyd.map(function(v) { result.push(v); }, e); | ||
a(1)(2)(3); | ||
assert.deepEqual(result, [10, 13, 16]); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
99864
24
1843
521
4