bacon.js — gérer efficacement les flux de données en javascript
TRANSCRIPT
Bacon.jsHow to handle JS streams
Rodolphe Belouin @rbelouinHuman Talks, Nantes, 2015-01-13
What do I do?
I work at Clever-Cloud and my job is to make developers happy.
The Clever-Cloud dashboard
We are doing lots of stuff, client-side
Example: the critical action button
Launch a rocket
Launch a rocket
Abort (5s,4s,3s…)
Rocket launched!
click
HTTP request
Launch a rocket (…)
click
var intervalId;
function startCountdown(onend) { var duration = 10; updateTheCountdownButton(duration);
intervalId = setInterval(function() {duration--;updateTheCountdownButton(duration);
if(duration == 0) { onend();
} }, 1000);}
The naive countdown
You get spaghetti code
var $performButton = document.querySelector("#critical-action");var $abortButton = document.querySelector("#abort-action");
$performButton.addEventListener("click", function() { startCountdown(function onend() { sendRequest(function(result) { /* The critical action is done */
}); });});
$abortButton.addEventListener(“click”, function() { /* Do some stuff to abort the critical action */});
A lot of asynchronous work
We need modularity and composition
Here comes Bacon.js
Click streams
var s_performClick = $(“button#perform-button”).asEventStream(“click”);
var s_abortClick = $(“button#abort-button”).asEventStream(“click”);
E E E
Abort action streamvar s_abortAction = s_performClick.flatMapLatest(function() { return s_abortClick;});
E
s_performClick
E
s_abortAction
E
s_abortClickE E
Waiting for a click
The final countdown streamvar s_countdown = s_performed.flatMapLatest(function() { var d = 10; var s_seconds = Bacon.interval(1000, 1); var s_remainingSeconds = s_seconds.scan(d, function(rem, sec) { return rem - sec; }); return s_remainingSeconds
.takeUntil(s_abortClick)
.takeWhile(function(countdown) { return countdown >= 0;
});});
The final countdown stream1
s_seconds1 11 1 111
s_abortClickE
s_remainingSeconds10 9 8 7 6 5 4 3
s_countdown10 9 8 7
Enjoy the stream POWAA!
HTTP requests streamsvar s_notAborted = s_countdown.filter(function(countdown) { return countdown == 0;}).take(1);
var s_performed = s_notAborted.flatMapLatest(function() { return Bacon.fromPromise($.post(“/critical”));});
E
s_notAborted
R
s_performed
HTTP request
Stop working on actions, and transform values
Hide or display buttons
s_performClick.onValue(function() { $performButton.hide(); $abortButton.show();});
s_abortClick.onValue(function() { $abortButton.hide(); $performButton.show();});
Display the countdown
s_countdown .map(function(seconds) { return "Abort (" + seconds + "s)"; }) .assign($abortButton, "text");
Display a loader during a request
var s_loading = s_notAborted.awaiting(s_performed);s_loading.onValue(handleLoader($performButton));
s_notAbortedE
s_performedE
s_loadingfalse true false
HTTP request
Display a message when all is overs_notAborted.map(true).toProperty(false) .assign($abortButton, "attr", "disabled");
s_notAborted.map("The action has been done") .assign($abortButton, "text");
May the streams be with you
Questions?http://baconjs.github.io
https://github.com/baconjs/bacon.js
You can train online: http://learn-bacon.herokuapp.com/
I am Rodolphe Belouin. @rbelouin on Twitter & Github