SlideShare a Scribd company logo
Functional Reactive
Programming in JS
Mario Zupan
@mzupzup
Stefan Mayer
@stefanmayer13
Who are we?
@stefanmayer13 @mzupzup
Motivation
■ Technology stack re-evaluation
■ Lessons learned
■ Functional Programming
■ QCon NYC
What is Functional Reactive
Programming?
Reactive Manifesto
Reactive Manifesto
? ?
? ?
Functional Programming
■ Evaluation of mathematical functions
■ Avoid mutable state
■ Referential transparency
■ Avoid side-effects
■ Reusable functions over reusable object
■ Function composition over object
composition
Functional Programming
■ map
■ filter
■ mergeAll
■ reduce
■ zip
var data = [1, 2, 3, 4, 5];
var numbers = data.map(function (nr) {
return nr + 1;
});
//numbers = [2, 3, 4, 5, 6]
var data = [1, 2, 3, 4, 5, 6, 7];
var numbers = data.filter(function (nr) {
return nr % 2 === 0;
});
// numbers = [2, 4, 6]
var data = [1, 2, 3, 4, 5, 6, 7];
var numbers = data.map(function (nr) {
return nr + 1;
}).filter(function (nr) {
return nr % 2 === 0;
});
// numbers = [2, 4, 6, 8]
var data = [[1, 2], [3, 4], 5, [6], 7, 8];
var numbers = data.mergeAll();
// numbers = [1, 2, 3, 4, 5, 6, 7, 8]
var data = [{
numbers: [1, 2]
}, {
numbers: [3, 4]
};
var numbersFlatMap = data.flatMap(function (object) {
return object.numbers;
});
// numbersMap = [[1, 2], [3, 4]]
// numbersFlatMap = [1, 2, 3, 4]
var data = [1, 2, 3, 4];
var sum = data.reduce(function(acc, value) {
return acc + value;
});
// sum = 10
var data = [5, 7, 3, 4];
var min = data.reduce(function(acc, value) {
return acc < value ? acc : value;
});
// min = 3
var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
var array = Array.zip(array1, array2,
function(left, right) {
return [left, right];
});
// array = [[1, 4], [2, 5], [3, 6]]
Reactive Programming
■ Asynchronous data streams
■ Everything is a stream
● click events
● user inputs
● data from a server
■ streams rock!
Reactive Programming
F + R + P
■ Powerful Composition and Aggregation of
streams
■ Good fit for concurrent and event-driven
systems
■ Declarative
■ Easy to test
Observables
■ Stream of data over time
■ Hot vs Cold Observables
■ Asynchronous
■ Lazy
■ queryable, bufferable, pausable…
■ more than 120 operations
Observable Creation
Rx.Observable.fromArray([1, 2, 3]);
Rx.Observable.fromEvent(input, 'click');
Rx.Observable.fromEvent(eventEmitter, 'data', fn);
Rx.Observable.fromCallback(fs.exists);
Rx.Observable.fromNodeCallback(fs.exists);
Rx.Observable.fromPromise(somePromise);
Rx.Observable.fromIterable(function*() {yield 20});
var range = Rx.Observable.range(1, 3); // 1, 2, 3
var range = range.subscribe(
function(value) {},
function(error) {},
function() {}
);
Observable Basics
optional
var range = Rx.Observable.range(1, 10) // 1, 2, 3 ...
.filter(function(value) { return value % 2 === 0; })
.map(function(value) { return "<span>" + value + "</span>"; })
.takeLast(1);
var subscription = range.subscribe(
function(value) { console.log("last even value: " + value); });
// "last even value: <span>10</span>"
Observable Basics
Cold Observables
Hot Observables
Autocomplete
● Multiple requests
● Async results
● Race conditions
● State
● ...
Autocomplete 1/2
var keyup = Rx.Observable.fromEvent(input, 'keyup')
.map(function (e) {
return e.target.value; // map to text
})
.filter(function (input) {
return input.length > 2; // filter relevant values
})
.debounce(250)
.distinctUntilChanged() // only if changes
.flatMapLatest(doAsyncSearch() // do async search on server
.retry(3))
.takeUntil(cancelStream) // chancel stream
.subscribe(
function (data) { // do UI stuff },
function (error) { // do error handling }
);
Autocomplete 2/2
Drag & Drop 1/2
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');
var mousemove = Rx.Observable.fromEvent(document, 'mousemove');
var mouseup = Rx.Observable.fromEvent(dragTarget, 'mouseup');
mousedown.flatMap(function (md) {
// get starting coordinates
var startX = md.offsetX, startY = md.offsetY;
return mousemove.map(function (mm) {
// return the mouse distance from start
return {left: mm.clientX - startX, top: mm.clientY - startY };
}).takeUntil(mouseup);
}).subscribe(function (pos) {
// do UI stuff
});
Some Cool Stuff on Observables
.bufferWithTime(500)
.pausable(pauser), .pausableBuffered(..)
.repeat(3)
.skip(1), skipUntilWithTime(..)
.do() // for side-effects like logging
.onErrorResumeNext(second) // resume with other obs
.window() // project into windows
.timestamp() // add time for each value
.delay()
RxJS
Supported
■ IE6+
■ Chrome 4+
■ FireFox 1+
■ Node.js v0.4+
Size (minified & gzipped):
■ all - 23,1k
■ lite - 13,5k
■ compat - 12,5k
■ ES5 core - 12k
Framework Bridges
■ AngularJS
■ ReactJS
■ jQuery
■ ExtJS
■ NodeJS
■ Backbone
■ ...
Companies using Rx in Production
Alternatives to RxJS
■ BaconJS
■ Kefir
■ (Elm)
Conclusion
■ There is a learning curve
■ Great abstraction for async & events
■ Improves
● Readability
● Reusability
● Scalability
■ Both on the front- and backend
Image references
■ KefirJS - https://camo.githubusercontent.com/
■ BaconJS - http://baconjs.github.io
■ data stream - http://www.pharmmd.com/
■ Elm - http://elm-lang.org
■ Browsers - http://www.thechrisyates.com/
■ websocket logo - http://blog.appharbor.com/
■ drag n drop - http://dockphp.com/
■ f(x) - http://www.ylies.fr/
■ qcon - https://qconsf.com/
■ check sign - http://www.cclscorp.com
■ map - http://reactivex.io/
■ reactivex logo - http://reactivex.io
■ chuck norris - http://www.quickmeme.com/
■ sencha - http://www.sencha.com/
■ reactive companies - http://www.reactivex.io
■ filter reactive - https://raw.githubusercontent.com/wiki/ReactiveX/RxJava/
■ node logo - http://calebmadrigal.com/
■ extjs - http://marceloagustini.files.wordpress.com/
■ hot observables - http://blogs.msdn.com/
■ cold observables - http://blogs.msdn.com/
■ backbone - http://2.bp.blogspot.com/
■ reactjs - http://moduscreate.com/
■ angular - http://www.w3schools.com/
■ reactive diagram observables - http://buildstuff14.sched.org/event/9ead0e99b3c1c0edddec6c7c8d526125#.VHEgq5PF-kQ
■ reactivemanifesto - http://www.reactivemanifesto.org
Learning RxJS
■ RxKoans
○ https://github.com/Reactive-Extensions/RxJSKoans
■ learnRx
○ https://github.com/jhusain/learnrx
■ The Introduction to Reactive Programming you've been
missing
○ https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
■ rxMarbles
○ http://rxmarbles.com/
Thank you
@stefanmayer13
@mzupzup

More Related Content

PPTX
Functional Reactive Programming with RxJS
PPTX
Luis Atencio on RxJS
PDF
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
PDF
rx.js make async programming simpler
PDF
RxJS - The Reactive extensions for JavaScript
PDF
RxJS 5 in Depth
PDF
RxJS Evolved
PDF
Functional Reactive Programming
Functional Reactive Programming with RxJS
Luis Atencio on RxJS
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
rx.js make async programming simpler
RxJS - The Reactive extensions for JavaScript
RxJS 5 in Depth
RxJS Evolved
Functional Reactive Programming

What's hot (20)

PDF
Add Some Fun to Your Functional Programming With RXJS
PDF
Cascadia.js: Don't Cross the Streams
PPTX
Storm is coming
KEY
W3C HTML5 KIG-How to write low garbage real-time javascript
PDF
The power of streams in node js
PDF
What they don't tell you about JavaScript
PDF
Compose Async with RxJS
PPTX
IOT Firmware: Best Pratices
PDF
Sujet bac info 2013 g1, g2 et g3 avec correction
PDF
RxJS101 - What you need to know to get started with RxJS tomorrow
ODP
Event Loop in Javascript
PPT
Tilting Google Maps and MissileLauncher
PDF
10 chapter6 heaps_priority_queues
PPTX
HAB Software Woes
PDF
Bristol 2009 q1_wright_steve
PDF
Cocoa勉強会23-識別情報の変換〜文字エンコードとデータタイプ
PDF
Functional Reactive Programming / Compositional Event Systems
ODP
Daniel Sikar: Hadoop MapReduce - 06/09/2010
PDF
Ganga: an interface to the LHC computing grid
PPTX
Synapse india dotnet development overloading operater part 4
Add Some Fun to Your Functional Programming With RXJS
Cascadia.js: Don't Cross the Streams
Storm is coming
W3C HTML5 KIG-How to write low garbage real-time javascript
The power of streams in node js
What they don't tell you about JavaScript
Compose Async with RxJS
IOT Firmware: Best Pratices
Sujet bac info 2013 g1, g2 et g3 avec correction
RxJS101 - What you need to know to get started with RxJS tomorrow
Event Loop in Javascript
Tilting Google Maps and MissileLauncher
10 chapter6 heaps_priority_queues
HAB Software Woes
Bristol 2009 q1_wright_steve
Cocoa勉強会23-識別情報の変換〜文字エンコードとデータタイプ
Functional Reactive Programming / Compositional Event Systems
Daniel Sikar: Hadoop MapReduce - 06/09/2010
Ganga: an interface to the LHC computing grid
Synapse india dotnet development overloading operater part 4
Ad

Viewers also liked (7)

PDF
Running Containerized Node.js Services on AWS Elastic Beanstalk
PDF
Functional Programming Patterns for the Pragmatic Programmer
PDF
Quality and Software Design Patterns
PDF
Functional Programming Principles & Patterns
PPT
Software design methodologies
PDF
Functional Programming Patterns (NDC London 2014)
PPTX
Running Containerized Node.js Services on AWS Elastic Beanstalk
Functional Programming Patterns for the Pragmatic Programmer
Quality and Software Design Patterns
Functional Programming Principles & Patterns
Software design methodologies
Functional Programming Patterns (NDC London 2014)
Ad

Similar to Functional Reactive Programming in JavaScript (20)

PDF
RxJava on Android
PDF
Beyond Breakpoints: A Tour of Dynamic Analysis
PPTX
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
PDF
RxJava applied [JavaDay Kyiv 2016]
KEY
JavaScript Growing Up
PDF
Integration-Monday-Stateful-Programming-Models-Serverless-Functions
PDF
Douglas Crockford: Serversideness
PDF
Advanced JavaScript Development
PDF
SF Big Analytics 20191112: How to performance-tune Spark applications in larg...
PDF
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
PDF
pg_proctab: Accessing System Stats in PostgreSQL
PDF
pg_proctab: Accessing System Stats in PostgreSQL
PDF
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
PDF
Functional Web Development
PDF
Analytics with Spark
PDF
Rxjs kyivjs 2015
PDF
Designing The Right Schema To Power Heap (PGConf Silicon Valley 2016)
PDF
PERFORMANCE_SCHEMA and sys schema
PDF
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
PDF
JavaScript for Web Analysts
RxJava on Android
Beyond Breakpoints: A Tour of Dynamic Analysis
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
RxJava applied [JavaDay Kyiv 2016]
JavaScript Growing Up
Integration-Monday-Stateful-Programming-Models-Serverless-Functions
Douglas Crockford: Serversideness
Advanced JavaScript Development
SF Big Analytics 20191112: How to performance-tune Spark applications in larg...
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
pg_proctab: Accessing System Stats in PostgreSQL
pg_proctab: Accessing System Stats in PostgreSQL
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
Functional Web Development
Analytics with Spark
Rxjs kyivjs 2015
Designing The Right Schema To Power Heap (PGConf Silicon Valley 2016)
PERFORMANCE_SCHEMA and sys schema
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
JavaScript for Web Analysts

Recently uploaded (20)

PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Nekopoi APK 2025 free lastest update
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
history of c programming in notes for students .pptx
PPT
Introduction Database Management System for Course Database
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
AI in Product Development-omnex systems
PPTX
ISO 45001 Occupational Health and Safety Management System
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Operating system designcfffgfgggggggvggggggggg
PPTX
L1 - Introduction to python Backend.pptx
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
ManageIQ - Sprint 268 Review - Slide Deck
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Odoo POS Development Services by CandidRoot Solutions
Softaken Excel to vCard Converter Software.pdf
Nekopoi APK 2025 free lastest update
How to Choose the Right IT Partner for Your Business in Malaysia
Navsoft: AI-Powered Business Solutions & Custom Software Development
history of c programming in notes for students .pptx
Introduction Database Management System for Course Database
CHAPTER 2 - PM Management and IT Context
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
AI in Product Development-omnex systems
ISO 45001 Occupational Health and Safety Management System
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Which alternative to Crystal Reports is best for small or large businesses.pdf
Operating system designcfffgfgggggggvggggggggg
L1 - Introduction to python Backend.pptx
Wondershare Filmora 15 Crack With Activation Key [2025
How to Migrate SBCGlobal Email to Yahoo Easily
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...

Functional Reactive Programming in JavaScript

  • 1. Functional Reactive Programming in JS Mario Zupan @mzupzup Stefan Mayer @stefanmayer13
  • 3. Motivation ■ Technology stack re-evaluation ■ Lessons learned ■ Functional Programming ■ QCon NYC
  • 4. What is Functional Reactive Programming?
  • 7. Functional Programming ■ Evaluation of mathematical functions ■ Avoid mutable state ■ Referential transparency ■ Avoid side-effects ■ Reusable functions over reusable object ■ Function composition over object composition
  • 8. Functional Programming ■ map ■ filter ■ mergeAll ■ reduce ■ zip
  • 9. var data = [1, 2, 3, 4, 5]; var numbers = data.map(function (nr) { return nr + 1; }); //numbers = [2, 3, 4, 5, 6]
  • 10. var data = [1, 2, 3, 4, 5, 6, 7]; var numbers = data.filter(function (nr) { return nr % 2 === 0; }); // numbers = [2, 4, 6]
  • 11. var data = [1, 2, 3, 4, 5, 6, 7]; var numbers = data.map(function (nr) { return nr + 1; }).filter(function (nr) { return nr % 2 === 0; }); // numbers = [2, 4, 6, 8]
  • 12. var data = [[1, 2], [3, 4], 5, [6], 7, 8]; var numbers = data.mergeAll(); // numbers = [1, 2, 3, 4, 5, 6, 7, 8]
  • 13. var data = [{ numbers: [1, 2] }, { numbers: [3, 4] }; var numbersFlatMap = data.flatMap(function (object) { return object.numbers; }); // numbersMap = [[1, 2], [3, 4]] // numbersFlatMap = [1, 2, 3, 4]
  • 14. var data = [1, 2, 3, 4]; var sum = data.reduce(function(acc, value) { return acc + value; }); // sum = 10
  • 15. var data = [5, 7, 3, 4]; var min = data.reduce(function(acc, value) { return acc < value ? acc : value; }); // min = 3
  • 16. var array1 = [1, 2, 3]; var array2 = [4, 5, 6]; var array = Array.zip(array1, array2, function(left, right) { return [left, right]; }); // array = [[1, 4], [2, 5], [3, 6]]
  • 17. Reactive Programming ■ Asynchronous data streams ■ Everything is a stream ● click events ● user inputs ● data from a server ■ streams rock!
  • 19. F + R + P ■ Powerful Composition and Aggregation of streams ■ Good fit for concurrent and event-driven systems ■ Declarative ■ Easy to test
  • 20. Observables ■ Stream of data over time ■ Hot vs Cold Observables ■ Asynchronous ■ Lazy ■ queryable, bufferable, pausable… ■ more than 120 operations
  • 21. Observable Creation Rx.Observable.fromArray([1, 2, 3]); Rx.Observable.fromEvent(input, 'click'); Rx.Observable.fromEvent(eventEmitter, 'data', fn); Rx.Observable.fromCallback(fs.exists); Rx.Observable.fromNodeCallback(fs.exists); Rx.Observable.fromPromise(somePromise); Rx.Observable.fromIterable(function*() {yield 20});
  • 22. var range = Rx.Observable.range(1, 3); // 1, 2, 3 var range = range.subscribe( function(value) {}, function(error) {}, function() {} ); Observable Basics optional
  • 23. var range = Rx.Observable.range(1, 10) // 1, 2, 3 ... .filter(function(value) { return value % 2 === 0; }) .map(function(value) { return "<span>" + value + "</span>"; }) .takeLast(1); var subscription = range.subscribe( function(value) { console.log("last even value: " + value); }); // "last even value: <span>10</span>" Observable Basics
  • 26. Autocomplete ● Multiple requests ● Async results ● Race conditions ● State ● ...
  • 27. Autocomplete 1/2 var keyup = Rx.Observable.fromEvent(input, 'keyup') .map(function (e) { return e.target.value; // map to text }) .filter(function (input) { return input.length > 2; // filter relevant values }) .debounce(250)
  • 28. .distinctUntilChanged() // only if changes .flatMapLatest(doAsyncSearch() // do async search on server .retry(3)) .takeUntil(cancelStream) // chancel stream .subscribe( function (data) { // do UI stuff }, function (error) { // do error handling } ); Autocomplete 2/2
  • 29. Drag & Drop 1/2 var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown'); var mousemove = Rx.Observable.fromEvent(document, 'mousemove'); var mouseup = Rx.Observable.fromEvent(dragTarget, 'mouseup');
  • 30. mousedown.flatMap(function (md) { // get starting coordinates var startX = md.offsetX, startY = md.offsetY; return mousemove.map(function (mm) { // return the mouse distance from start return {left: mm.clientX - startX, top: mm.clientY - startY }; }).takeUntil(mouseup); }).subscribe(function (pos) { // do UI stuff });
  • 31. Some Cool Stuff on Observables .bufferWithTime(500) .pausable(pauser), .pausableBuffered(..) .repeat(3) .skip(1), skipUntilWithTime(..) .do() // for side-effects like logging .onErrorResumeNext(second) // resume with other obs .window() // project into windows .timestamp() // add time for each value .delay()
  • 32. RxJS Supported ■ IE6+ ■ Chrome 4+ ■ FireFox 1+ ■ Node.js v0.4+ Size (minified & gzipped): ■ all - 23,1k ■ lite - 13,5k ■ compat - 12,5k ■ ES5 core - 12k
  • 33. Framework Bridges ■ AngularJS ■ ReactJS ■ jQuery ■ ExtJS ■ NodeJS ■ Backbone ■ ...
  • 34. Companies using Rx in Production
  • 35. Alternatives to RxJS ■ BaconJS ■ Kefir ■ (Elm)
  • 36. Conclusion ■ There is a learning curve ■ Great abstraction for async & events ■ Improves ● Readability ● Reusability ● Scalability ■ Both on the front- and backend
  • 37. Image references ■ KefirJS - https://camo.githubusercontent.com/ ■ BaconJS - http://baconjs.github.io ■ data stream - http://www.pharmmd.com/ ■ Elm - http://elm-lang.org ■ Browsers - http://www.thechrisyates.com/ ■ websocket logo - http://blog.appharbor.com/ ■ drag n drop - http://dockphp.com/ ■ f(x) - http://www.ylies.fr/ ■ qcon - https://qconsf.com/ ■ check sign - http://www.cclscorp.com ■ map - http://reactivex.io/ ■ reactivex logo - http://reactivex.io ■ chuck norris - http://www.quickmeme.com/ ■ sencha - http://www.sencha.com/ ■ reactive companies - http://www.reactivex.io ■ filter reactive - https://raw.githubusercontent.com/wiki/ReactiveX/RxJava/ ■ node logo - http://calebmadrigal.com/ ■ extjs - http://marceloagustini.files.wordpress.com/ ■ hot observables - http://blogs.msdn.com/ ■ cold observables - http://blogs.msdn.com/ ■ backbone - http://2.bp.blogspot.com/ ■ reactjs - http://moduscreate.com/ ■ angular - http://www.w3schools.com/ ■ reactive diagram observables - http://buildstuff14.sched.org/event/9ead0e99b3c1c0edddec6c7c8d526125#.VHEgq5PF-kQ ■ reactivemanifesto - http://www.reactivemanifesto.org
  • 38. Learning RxJS ■ RxKoans ○ https://github.com/Reactive-Extensions/RxJSKoans ■ learnRx ○ https://github.com/jhusain/learnrx ■ The Introduction to Reactive Programming you've been missing ○ https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 ■ rxMarbles ○ http://rxmarbles.com/