Functional
Reactive Programming
with Bacon.js
Dimitry Solovyov
@dimituri
Imperative Functional
x=x+1 f(x) = … f(x + 1) …
♥ 3
×
val
t
Client-side programming is all about
time-varying values
"#$%
Input Disk Network Timers
(30,30) (50,40) (80,50)
pub/sub
Observer
$.Deferred
Excel cell
…
JavaScript
https://github.com/baconjs/bacon.js
Elm (Haskell-like)
http://elm-lang.org
ClojureScript
https://github.com/tailrecursion/javelin
map
1 2 3 4 5
map x
=>
x
*
2
2 4 6 8 10
filter*
* I didn’t find a good picture for “filter”, sorry.
However, here is my cat.
1 2 3 4 5
filter x
=>
(x
%
2
==
0)
× 2 × 4 ×
Mouse move
var
area
=
$('#area');
var
moveS
=
area.asEventStream('mousemove');
map
Mouse move Coordinates
var
area
=
$('#area');
var
coords
=
area.asEventStream('mousemove')
.map(function(e)
{
return
[e.offsetX,
e.offsetY];
});
map filter
Mouse move Coordinates In hitbox
var
area
=
$('#area');
var
inHitbox
=
area.asEventStream('mousemove')
.map(function(e)
{
return
[e.offsetX,
e.offsetY];
}).filter(function(coords)
{
return
hitbox.contains(coords);
});
Mouse click
Mouse move
var
area
=
$('#area');
var
moveS
=
area.asEventStream('mousemove');
var
clickS
=
area.asEventStream('click');
sampledBy
Mouse click
Mouse move Click info
var
area
=
$('#area');
var
moveS
=
area.asEventStream('mousemove');
var
clickS
=
area.asEventStream('click');
var
clickInfo
=
moveS.toProperty()
.sampledBy(clickS,
function(moveE,
clickE)
{
return
[moveE.offsetX,
moveE.offsetY];
});
sampledBy onValue
Mouse click
Mouse move Click info Element text
var
area
=
$('#area');
var
moveS
=
area.asEventStream('mousemove');
var
clickS
=
area.asEventStream('click');
moveS.toProperty()
.sampledBy(clickS,
function(moveE,
clickE)
{
return
[moveE.offsetX,
moveE.offsetY];
}).onValue(area,
'text');
fold
1 2 3 4 5
fold (a,
x)
=>
{
a
+
x
}
a= 1 2 4 7 11 16
Key press
var
keyS
=
$(window).asEventStream('keypress');
map
Key press Character
var
keyS
=
$(window).asEventStream('keypress');
var
charS
=
keyS.map(function(e)
{
return
String.fromCharCode(e.charCode);
});
map fold
Key press Character Typed text
var
keyS
=
$(window).asEventStream('keypress');
var
typedText
=
keyS.map(function(e)
{
return
String.fromCharCode(e.charCode);
}).scan('',
function(s,
chr)
{
return
s
+
chr;
});
filter
Keyboard Arrow keys
sampledBy fold
Arrow keys
Seconds Key info Game state
onValue
Game state Canvas
Juha Paananen
“FRP with Bacon.js”
http://www.ustream.tv/recorded/29299079
Bret Victor
“Inventing on Principle”
http://vimeo.com/36579366
THE END!
SIGN
WITH ALS
DEF
ERR
var
df
=
$.Deferred();
ED
df.then(null,
null,
function(x)
{
return
x
*
3;
}).progress(function(x)
{
console.log(x);
});
df.then(null,
null,
function(x)
{
return
x
*
4;
}).progress(function(x)
{
console.log(x);
});
df.notify(3);
YOU
WITH R OWN
var
Signal
=
function(value)
{
PUR
this.value
=
value;
E JS
this.callbacks
=
[];
};
Signal.prototype.notify
=
function(value)
{
if
(value
==
null)
{
return;
}
this.value
=
value;
for
(var
i
=
0;
i
<
this.callbacks.length;
i++)
{
var
callback
=
this.callbacks[i];
callback(value);
}
};
MAP
WITH PING
PUR
E JS
Signal.prototype.map
=
function(fn)
{
var
childS
=
new
Signal();
if
(this.value
!=
null)
{
childS.value
=
fn(this.value);
}
this.callbacks.push(function(newValue)
{
childS.notify(fn(newValue));
});
return
childS;
};