Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Max Klymyshyn
CartFresh
Fighting async JavaScript
CartFresh
GVMachinesInc.
‣ GroceryDeliverystartup
‣ WorkinginUkraineas ZAKAZ.UA(Kiev,
Dnepropetrovsk,Kharkiv)andas CartFre...
theproblem
AsynchronousI/O
asynchronousI/OleadstocallbackAPI’s,
which leadtonestedlambdas,
which leadto…thepyramidof doom:
range.on("preheat", function() {
pot.on("boil", function() {
rice.on("cooked", function() {
dinner.serve(rice);
});
});
})...
clusterfuck.
Understandingthecode
‣ IBM1989: 50%of theeffortinaccomplishinga taskfortheprogrammeris
towardsunderstandingthesystem
‣ BellLabs1992:60%-80%of t...
Promises
var greetingPromise = sayHello();
greetingPromise
.then(addExclamation)
.then(function (greeting) {
console.log(g...
function loadStory() {
return getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
return story.chap...
Await
async function loadStory() {
try {
let story = await getJSON('story.json');
addHtmlToPage(story.heading);
for (let c...
FRP/RxJS
const $input = $('#input');
const $results = $('#results');
/* Only get the value from each key up */
var keyups ...
Actormodel
(function () {
var spawn = WebActors.spawn;
var receive = WebActors.receive;
var send = WebActors.send, ANY = W...
CSP
Communicatingsequentialprocesses
CSP
‣ initially isaformallanguagefordescribingpatterns
of interactionin concurrentsystems
‣ firstdescribedina1978paperby T...
Key points
‣ CSPcreatedforcommunicatingbetweendifferent
componentsandsubsystems
‣ CSPsolveproblemof coordinatinganythingas...
example
import {chan, take, CLOSED, timeout, put} from "js-csp";
var ch = chan();
go(function*() {
var val;
while((val = yield tak...
real-world
export class Suggest extends React.Component {
constructor(props) {
super(props);
this.state = {active: -1, suggests: prop...
function listen(el, type) {
var ch = chan();
el.addEventListener(type, e => {
putAsync(ch, [e.keyCode, el.value]);
e.preve...
synccode
Toolstowrite in syncstyle?
‣ Promises,Promiseswith generators
‣ Generators
‣ Async/wait
‣ Usingjs-csp(withgenerators)
synccode
withjs-csp
Tools
‣ Events
‣ XMLHttpRequest/HTTP
‣ WebSockets
‣ Timers
‣ Webworkers
Runtimeforlow-levelasync operations:getURL
import {buffers, go, chan, putAsync, operations} from "js-csp";
export function listen(el, type, options={}) {
/**
* Trans...
import {go, take, timeout, CLOSED, close, chan, buffers} from "js-csp";
import {listen} from "./runtime.js";
var mousemove...
import {buffers, go, chan, putAsync, take,} from "js-csp";
export function json(options) {
var ch = chan();
go(function * ...
Features
‣ Channelbuffering:fixedsize,sliding,dropping
‣ pollvalues:takingimmediately
‣ alts:waitforvalueor executesecondo...
Extra features
‣ Reducechannelvalues
‣ splitvaluesof channels
‣ merge channels
‣ mult– supply valuesintotwochannels
‣ Pub/...
thanks.
@maxmaxmaxmax
References
1.No,YouarenotDumb!Programmersdospendalotof timeUnderstandingCode…
http://blog.architexa.com/2010/05/no-you-are...
Fighting async JavaScript (CSP)
Fighting async JavaScript (CSP)
Fighting async JavaScript (CSP)
Fighting async JavaScript (CSP)
Fighting async JavaScript (CSP)
Upcoming SlideShare
Loading in …5
×

Fighting async JavaScript (CSP)

903 views

Published on

How to beat asynchronicity in JavaScript, especially using CSP-paradigm (Communicating Sequential Processes) and js-csp library

Published in: Software
  • Be the first to comment

Fighting async JavaScript (CSP)

  1. 1. Max Klymyshyn CartFresh Fighting async JavaScript
  2. 2. CartFresh GVMachinesInc. ‣ GroceryDeliverystartup ‣ WorkinginUkraineas ZAKAZ.UA(Kiev, Dnepropetrovsk,Kharkiv)andas CartFresh(Boston, US) ‣ React.jsonfront-end ‣ Python onback-end
  3. 3. theproblem
  4. 4. AsynchronousI/O asynchronousI/OleadstocallbackAPI’s, which leadtonestedlambdas, which leadto…thepyramidof doom:
  5. 5. range.on("preheat", function() { pot.on("boil", function() { rice.on("cooked", function() { dinner.serve(rice); }); }); }); Pyramidof doom
  6. 6. clusterfuck.
  7. 7. Understandingthecode
  8. 8. ‣ IBM1989: 50%of theeffortinaccomplishinga taskfortheprogrammeris towardsunderstandingthesystem ‣ BellLabs1992:60%-80%of theirtime understandingcode,20% asthe developersgainexperiencewith currentcodebase ‣ NationalResearchCouncil1997(Canada):over25% of theirtimeeither searchingfor orlookingatcode ‣ Microsoft2006:50% ‣ PeterHallam2006:70%duringpersonal experiment ‣ Microsoft2007:65%(survey) [1]
  9. 9. Promises var greetingPromise = sayHello(); greetingPromise .then(addExclamation) .then(function (greeting) { console.log(greeting); // hello world!!!! }, function(error) { // 'uh oh: something bad happened console.error('uh oh: ', error); });
  10. 10. function loadStory() { return getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); return story.chapterURLs.map(getJSON) .reduce(function(chain, chapterPromise) { return chain.then(function() { return chapterPromise; }).then(function(chapter) { addHtmlToPage(chapter.html); }); }, Promise.resolve()); }).then(function() { addTextToPage("All done"); }).catch(function(err) { addTextToPage("Argh, broken: " + err.message); }).then(function() { document.querySelector('.spinner').style.display = 'none'; }); }
  11. 11. Await async function loadStory() { try { let story = await getJSON('story.json'); addHtmlToPage(story.heading); for (let chapter of story.chapterURLs.map(getJSON)) { addHtmlToPage((await chapter).html); } addTextToPage("All done"); } catch (err) { addTextToPage("Argh, broken: " + err.message); } document.querySelector('.spinner').style.display = 'none'; } (async function() { await loadStory(); console.log("Yey, story successfully loaded!"); }()); [5] [6] [7]
  12. 12. FRP/RxJS const $input = $('#input'); const $results = $('#results'); /* Only get the value from each key up */ var keyups = Rx.Observable.fromEvent($input, 'keyup') .pluck('target', 'value') .filter(text => text.length > 2 ); /* Now debounce the input for 500ms */ var debounced = keyups.debounce(500 /* ms */); /* Now get only distinct values, so we eliminate the arrows and other control characters */ var distinct = debounced.distinctUntilChanged(); [4]
  13. 13. Actormodel (function () { var spawn = WebActors.spawn; var receive = WebActors.receive; var send = WebActors.send, ANY = WebActors.ANY; function aCallback() { receive(ANY, function (message) { alert(message); }); } actor = spawn(aCallback); // create an actor send(actor, "a message"); // send it a message })(); [2] [3]
  14. 14. CSP Communicatingsequentialprocesses
  15. 15. CSP ‣ initially isaformallanguagefordescribingpatterns of interactionin concurrentsystems ‣ firstdescribedina1978paperby TonyHoare ‣ influentialinthe designof the occam,Go,Limbo ‣ core.asyncin clojure ‣ js-cspforJS
  16. 16. Key points ‣ CSPcreatedforcommunicatingbetweendifferent componentsandsubsystems ‣ CSPsolveproblemof coordinatinganythingasynchronous ‣ CSPalongsideotherssolveproblemof easy-to- understandcode
  17. 17. example
  18. 18. import {chan, take, CLOSED, timeout, put} from "js-csp"; var ch = chan(); go(function*() { var val; while((val = yield take(ch)) !== CLOSED) { console.log(val); } }); go(function*() { yield put(ch, 1); yield take(timeout(1000)); yield put(ch, 2); ch.close(); }); [8]
  19. 19. real-world
  20. 20. export class Suggest extends React.Component { constructor(props) { super(props); this.state = {active: -1, suggests: props.suggests}} componentWillReceiveProps(nextProps) { switch(nextProps.code) { case 38: this.setState({active: Math.max(-1, this.state.active - 1)}); break; case 40: this.setState({ active: Math.min(this.props.suggests.length - 1, this.state.active + 1)}); break; case 13: search(this.props.suggests[this.state.active]); this.setState({suggests: []}); break; default: this.setState({suggests: nextProps.suggests}); } } render() { return (<ul className="dropdown dropdown-menu"> {this.state.suggests.map((e, n) => <li key={e} className={...}><a href="#">{e}</a></li>)} </ul>); }}
  21. 21. function listen(el, type) { var ch = chan(); el.addEventListener(type, e => { putAsync(ch, [e.keyCode, el.value]); e.preventDefault(); }); return ch; } export function suggest(elem) { var el = elem[0]; go(function * () { var keydown = listen(el, 'keydown'); while(true) { var [code, value] = yield take(keydown); var response = yield take(Storage.sync([ ["store.suggest", {query: value}, {id: "suggest"}]])); ReactDOM.render( <Suggest suggests={response.suggests || []} code={code} value={value} />, document.getElementById("suggest")); } }); }
  22. 22. synccode
  23. 23. Toolstowrite in syncstyle? ‣ Promises,Promiseswith generators ‣ Generators ‣ Async/wait ‣ Usingjs-csp(withgenerators)
  24. 24. synccode withjs-csp
  25. 25. Tools ‣ Events ‣ XMLHttpRequest/HTTP ‣ WebSockets ‣ Timers ‣ Webworkers Runtimeforlow-levelasync operations:getURL
  26. 26. import {buffers, go, chan, putAsync, operations} from "js-csp"; export function listen(el, type, options={}) { /** * Translate events into CSP channel untile channel is not closed. */ var {channel, prevent} = options; var ch = channel || chan(); var listener = (e) => { if (ch.closed === true) el.removeEventListener(type, listener); else putAsync(ch, e); if (prevent === true) e.preventDefault(); } el.addEventListener(type, listener); return ch; }
  27. 27. import {go, take, timeout, CLOSED, close, chan, buffers} from "js-csp"; import {listen} from "./runtime.js"; var mousemove = listen(document, "mousemove", true, {channel: chan(buffers. dropping(1))}); var target = document.getElementById("coords"); go(function * () { var coords; while((coords = yield take(mousemove)) !== CLOSED) { target.innerHTML = `X=${coords.clientX} Y=${coords.clientY}`; } }); go(function * () { yield timeout(3000); yield mousemove.close(); target.innerHTML = 'interrupted.'; });
  28. 28. import {buffers, go, chan, putAsync, take,} from "js-csp"; export function json(options) { var ch = chan(); go(function * () { var value = yield take(request(options)); if(!(value instanceof Error)) { value = JSON.parse(value); } else { console.error("Can't get " + options.url, value); } putAsync(ch, value); }); return ch; }
  29. 29. Features ‣ Channelbuffering:fixedsize,sliding,dropping ‣ pollvalues:takingimmediately ‣ alts:waitforvalueor executesecondoperation Commonprocesses communication features
  30. 30. Extra features ‣ Reducechannelvalues ‣ splitvaluesof channels ‣ merge channels ‣ mult– supply valuesintotwochannels ‣ Pub/Submode ‣ Filteringwithpredicates and/ortransducers
  31. 31. thanks. @maxmaxmaxmax
  32. 32. References 1.No,YouarenotDumb!Programmersdospendalotof timeUnderstandingCode… http://blog.architexa.com/2010/05/no-you-are-not-dumb-programmers-do-spend-a-lot-of-time-understanding-code/ 2.AnActormodelexamplewithAkka.NET http://blog.geist.no/an-actor-model-example-with-akka-net/ 3.WebActors https://github.com/mental/webactors 4.TheReactiveExtensions forJavaScript (RxJS) https://github.com/Reactive-Extensions/RxJS 5.ES7asyncfunctions-astepin the wrongdirection https://spion.github.io/posts/es7-async-await-step-in-the-wrong-direction.html 6.Why coroutineswon’tworkon theweb http://calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web/ 7.ImplementationStrategiesfor First-ClassContinuations* http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=3668F1FC41AF1C1880B3062100057381?doi=10.1.1.70.9076&rep=rep1&type=pdf 8.Taming theAsynchronous Beast withCSPChannelsinJavaScript http://jlongster.com/Taming-the-Asynchronous-Beast-with-CSP-in-JavaScript

×