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.

JS Design Patterns & Reactive Programming

858 views

Published on

The presentation about Reactive programming and JS resign patterns presented at the May BucharestJS Meetup.
Link here: http://www.meetup.com/BucharestJS/events/231030252/

Published in: Technology
  • Your customer service is one of the best experiences I have had. Thanks again. ➜➜➜ https://w.url.cn/s/Ayy1McS
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

JS Design Patterns & Reactive Programming

  1. 1. JS DESIGN PATTERNS & REACTIVE PROGRAMMING
  2. 2. The implementation of a design pattern per day keeps the angry developer away -Old Chinese proverb
  3. 3. WHY USE ? ➤ easy way to refer to a very specific implementation of code ➤ can help to thwart minor issues that can create major problems later down the road ➤ Patterns exemplify a level of sophistication that can provide both performance boosts and reduction of excess memory usage ➤ Patterns established through rigorous testing which means they are, for the most part, "tried and true" and do aid in solving a particular type of problem
  4. 4. DESIGN PATTERN CATEGORIES
  5. 5. This category deals directly with object initialisation procedures focusing on the creation of situation-specific objects. It works to solve the problem of how objects are created by adding a layer to this process CREATIONAL DESIGN PATTERNS image credit: https://addyosmani.com/resources/essentialjsdesignpatterns/book/#categoriesofdesignp
  6. 6. SINGLETON ➤ Advantages ➤ Reduced memory footprint ➤ Single point of access ➤ Delayed initialisation that prevents instantiation until required ➤ Disadvantages ➤ Once instantiated, they're hardly ever “reset" ➤ Harder to unit test and sometimes introduces hidden dependencies var mySingleton = ( function( window, undefined ) { var instance = null; // revealing module pattern that handles initialization of our new module function initializeNewModule() { function myMethod() { alert( 'my method' ); } function myOtherMethod() { alert( 'my other method' ); } return { someMethod : myMethod, someOtherMethod : myOtherMethod }; } // handles the prevention of additional instantiations function getInstance() { if( ! instance ) { instance = new initializeNewModule(); } return instance; } return { getInstance : getInstance }; } )( window ); // example usage mySingleton.getInstance().someMethod(); // alerts "my method" mySingleton.getInstance().someOtherMethod(); // alerts "my other method"
  7. 7. FACTORY ➤ Advantages ➤ Makes complex object creation easy through an interface that can bootstrap this process for you ➤ Great for generating different objects based on the environment ➤ Practical for components that require similar instantiation or methods ➤ Great for decoupling components by bootstrapping the instantiation of a different object to carry out work for particular instances ➤ Disadvantages ➤ Unit testing can be difficult as a direct result of the object creation process being hidden by the factory methods function CarDoor( options ) { this.color = options.color || 'red'; this.side = options.side || 'right'; this.hasPowerWindows = options.hasPowerWindows || true; } function CarSeat( options ) { this.color = options.color || 'gray'; this.material = options.material || 'leather'; this.isReclinable = options.isReclinable || true; } function CarPartFactory() {} CarPartFactory.prototype.createPart = function createCarPart( options ) { var parentClass = null; if( options.partType === 'door' ) { parentClass = CarDoor; } else if( options.partType === 'seat' ) { parentClass = CarSeat; } if( parentClass === null ) { return false; } return new parentClass( options ); } // example usage var myPartFactory = new CarPartFactory(); var seat = myPartFactory.createPart( { partType : 'seat', material : 'leather', color : 'blue', isReclinable : false } ); // outputs: true console.log( seat instanceof CarSeat ); // outputs a CarSeat object with material "leather", color "blue", isReclinable "false" console.log( seat );
  8. 8. REVEALING MODULE ➤ Advantages ➤ Cleaner approach for developers ➤ Supports private data ➤ Less clutter in the global namespace ➤ Localisation of functions and variables through closures ➤ The syntax of our scripts are even more consistent ➤ Explicitly defined public methods and variables which lead to increased readability ➤ Disadvantages ➤ Private methods and functions lose extendability since they are unaccessible ➤ It's harder to patch public methods and variables that are referred to by something private var MyModule = ( function( window, undefined ) { function myMethod() { alert( 'my method' ); } function myOtherMethod() { alert( 'my other method' ); } // explicitly return public methods when this object is instantiated return { myMethod : myMethod, }; } )( window ); // example usage MyModule.myMethod(); // alerts "my method" MyModule.myOtherMethod(); // undefined
  9. 9. STRUCTURAL DESIGN PATTERNS This category is concerned with object composition and to identify simple ways to realise relationships between different objects. It helps ensure that when one part of a system changes, the entire structure of the system doesn't need to do the same. image credit: https://addyosmani.com/resources/essentialjsdesignpatterns/book/#categoriesofdesignp
  10. 10. THE FACADE PATTERN➤ Advantages ➤ Enhances security for your web application ➤ Works well in combination with other patterns ➤ Makes it easy to patch internals ➤ Provides a simpler public interface ➤ Proven useful for other major libraries such as jQuery ➤ Disadvantages ➤ Performance impact // a facade that masks the various browser-specific methods function addEvent( element, event, callback ) { if( window.addEventListener ) { element.addEventListener( event, callback, false ); } else if( document.attachEvent ) { element.attachEvent( 'on' + event, callback ); } else { element[ 'on' + event ] = callback; } }
  11. 11. DECORATOR ➤ Advantages ➤ Can be used transparently ➤ Is fairly flexible ➤ Avoids the need to rely on large numbers of subclasses to get the same benefits. ➤ Disadvantages ➤ Can complicate the application architecture if poorly managed ➤ Introduces many small, but similar objects into our namespace // A vehicle constructor function Vehicle( vehicleType ){ // some sane defaults this.vehicleType = vehicleType || "car"; this.model = "default"; this.license = "00000-000"; } // Test instance for a basic vehicle var testInstance = new Vehicle( "car" ); console.log( testInstance ); // vehicle: car, model:default, license: 00000-000 var truck = new Vehicle( "truck" ); // New functionality we're decorating vehicle with truck.setModel = function( modelName ){ this.model = modelName; }; truck.setColor = function( color ){ this.color = color; }; // Test the value setters and value assignment works correctly truck.setModel( "CAT" ); truck.setColor( "blue" ); console.log( truck ); // vehicle:truck, model:CAT, color: blue // Demonstrate "vehicle" is still unaltered var secondInstance = new Vehicle( "car" ); console.log( secondInstance ); // vehicle: car, model:default, license: 00000-000
  12. 12. BEHAVIOURAL DESIGN PATTERNS Behavioural design patterns focus on improving or streamlining through the identification of common communication patterns between various objects image credit: https://addyosmani.com/ resources/essentialjsdes ignpatterns/book/#categ oriesofdesignpatterns
  13. 13. THE MEDIATOR PATTERNThis pattern usually implements a single object that becomes a shared resource through all of the different pieces of an application. ➤ Advantages ➤ Reduces the communication relationship from "many-to-many" to “many-to-one" ➤ Helps us pinpoint dependencies ➤ Excellent at decoupling objects which often promotes smaller, reusable components ➤ Disadvantages ➤ Introduces a single point of failure ➤ When modules communicate back and forth using a mediator pattern, it tends to become cumbersome and usually results in a clear performance hit var Mediator = ( function( window, undefined ) { function Mediator() { this._topics = {}; } Mediator.prototype.subscribe = function mediatorSubscribe( topic, callback ) { if( ! this._topics.hasOwnProperty( topic ) ) { this._topics[ topic ] = []; } this._topics[ topic ].push( callback ); return true; }; Mediator.prototype.unsubscribe = function mediatorUnsubscriBe( topic, callback ) { if( ! this._topics.hasOwnProperty( topic ) ) { return false; } for( var i = 0, len = this._topics[ topic ].length; i < len; i++ ) { if( this._topics[ topic ][ i ] === callback ) { this._topics[ topic ].splice( i, 1 ); return true; } } return false; }; Mediator.prototype.publish = function mediatorPublish() { var args = Array.prototype.slice.call( arguments ); var topic = args.shift(); if( ! this._topics.hasOwnProperty( topic ) ) { return false; } for( var i = 0, len = this._topics[ topic ].length; i < len; i++ ) { this._topics[ topic ][ i ].apply( undefined, args ); } return true; }; return Mediator; } )( window ); // example subscriber function var listener = function ExampleListener( myVariable ) { console.log( myVariable ); }; // example usages var myMediator = new Mediator(); myMediator.subscribe( 'some event', listener ); myMediator.publish( 'some event', 'foo bar' ); // console logs "foo bar"
  14. 14. THE OBSERVER PATTERNThis pattern implements a single object (the subject) that maintains a reference to a collection of objects (known as "observers") and broadcasts notifications when a change to state occurs. ➤ Advantages ➤ Helps us pinpoint dependencies ➤ Excellent at decoupling objects which often promotes smaller, reusable components ➤ Disadvantages ➤ Checking the integrity of your application can become difficult ➤ Requires deeper-level thinking of the relationship between the various components of an application ➤ Switching a subscriber from one publisher to another can be costly // build the Subject base class var Subject = ( function( window, undefined ) { function Subject() { this._list = []; } // this method will handle adding observers to the internal list Subject.prototype.observe = function observeObject( obj ) { console.log( 'added new observer' ); this._list.push( obj ); }; Subject.prototype.unobserve = function unobserveObject( obj ) { for( var i = 0, len = this._list.length; i < len; i++ ) { if( this._list[ i ] === obj ) { this._list.splice( i, 1 ); console.log( 'removed existing observer' ); return true; } } return false; }; Subject.prototype.notify = function notifyObservers() { var args = Array.prototype.slice.call( arguments, 0 ); for( var i = 0, len = this._list.length; i < len; i++ ) { this._list[ i ].next.apply( null, args ); } }; return Subject; } )( window ); // setup an object that fetchs stocks function StockGrabber() { var subject = new Subject(); this.addObserver = function addObserver( newObserver ) { subject.observe( newObserver ); }; this.removeObserver = function removeObserver( deleteObserver ) { subject.unobserve( deleteObserver ); }; this.fetchStocks = function fetchStocks() { // fake fetching the stocks var stocks = { aapl : 167.00, goog : 243.67, msft : 99.34 }; // notify our observers of the stock change subject.notify( stocks ); }; }
  15. 15. // define a couple of different observers var StockUpdaterComponent = { next : function() { console.log( '"next" called on StockUpdater with: ', arguments ); } }; var StockChartsComponent = { next : function() { console.log( '"next" called on StockCharts with: ', arguments ); } }; // example usage var stockApp = new StockGrabber(); stockApp.addObserver( StockUpdaterComponent ); stockApp.fetchStocks(); // console logs: "next" called on StockUpdater with... stockApp.addObserver( StockChartsComponent ); stockApp.fetchStocks(); // console logs: "next" called on StockUpdater with... "next" called on StockCarts with... stockApp.removeObserver( StockUpdaterComponent ); stockApp.fetchStocks(); // console logs: "next" called on StockCharts with... stockApp.removeObserver( StockChartsComponent ); stockApp.fetchStocks(); // does nothing; no observers THE OBSERVER PATTERNThis pattern implements a single object (the subject) that maintains a reference to a collection of objects (known as "observers") and broadcasts notifications when a change to state occurs. ➤ Advantages ➤ Helps us pinpoint dependencies ➤ Excellent at decoupling objects which often promotes smaller, reusable components ➤ Disadvantages ➤ Checking the integrity of your application can become difficult ➤ Requires deeper-level thinking of the relationship between the various components of an application ➤ Switching a subscriber from one publisher to another can be costly
  16. 16. THE ITERATOR PATTERNProvide a way to access the elements of an aggregate object sequentially without exposing its underlying representation ➤ Advantages ➤ provides a standardised way to iterate any iterable object ➤ allows developers to design looping constructs that are far more flexible and sophisticated ➤ Disadvantages ➤ needs custom implementation ➤ hard to generate consistency do to lack of native JS implementation of Interfaces var Iterator = function(items) { this.index = 0; this.items = items; } Iterator.prototype = { first: function() { this.reset(); return this.next(); }, next: function() { return this.items[this.index++]; }, hasNext: function() { return this.index <= this.items.length; }, reset: function() { this.index = 0; }, each: function(callback) { for (var item = this.first(); this.hasNext(); item = this.next()) { callback(item); } } } // log helper var log = (function() { var log = ""; return { add: function(msg) { log += msg + "n"; }, show: function() { alert(log); log = ""; } } })(); function run() { var items = ["one", 2, "circle", true, "Applepie"]; var iter = new Iterator(items); // using for loop for (var item = iter.first(); iter.hasNext(); item = iter.next()) { log.add(item); } log.add(""); // using Iterator's each method iter.each(function(item) { log.add(item); }); log.show(); }
  17. 17. JS REACTIVE PROGRAM MING“Everything is a stream”
  18. 18. BIG QUESTIONS ➤ What is Reactive Programming? ➤ A programming paradigm oriented around data flows and the propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used, and that the underlying execution model will automatically propagate changes through the data flow. ➤ Why should I consider adopting RP? ➤ It raises the level of abstraction of your code so you can focus on the interdependence of events that define the business logic, rather than having to constantly fiddle with a large amount of implementation details. Code in RP will likely be more concise ➤ What is a stream? ➤ Event buses or your typical click events are really an asynchronous event stream, on which you can observe and do some side effects. Reactive is that idea on steroids. You are able to create data streams of anything, not just from click and hover events. Streams are cheap and ubiquitous, anything can be a stream: variables, user inputs, properties, caches, data structures, etc. You can listen to that stream and react accordingly
  19. 19. A HTTP REQUEST OBSERVABLE let requestStream = Rx.Observable.just('https://api.github.com/users'); let responseStream = requestStream .flatMap((requestUrl) => { return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl)); }); responseStream.subscribe((response) => { // render `response` to the DOM however you wish }); ➤ What are we doing? 1. we create a simple stream from a url string 2. we subscribe / observe that stream 3. we get every event on that stream ( requestUrl ) and make an http get request 4. then we “observe”(make a observable object) from the promise 5. pass that to the responseStream variable 6. observe(subscribe) to the result of the http call
  20. 20. A DOM EVENT OBSERVABLE let domElement = document.querySelector('#someId'); let domElementObs = Rx.Observable.fromEvent(domElement, 'blur') .map((ev)=>ev.target.value); domElementObs.subscribe(ev => { console.log(ev); }); ➤ What are we doing? 1. we are creating an observable stream from the dom element’s “blur” event 2. we map / transform that event data so that we only get the input’s value 3. we subscribe / observe to the event stream and process the data.
  21. 21. FLATMAP IS YOUR BEST FRIEND let source = Rx.Observable.interval(100).take(10) .flatMap( (res) => { return Rx.Observable.timer(500).map(()=>res*2) } ); source.subscribe(x=>console.log(x)); ➤ Why? 1. It transforms multiple streams of observables into a single observable 2. It does that by applying a rule defined by you 3. It helps you keep things clean and easy to understand
  22. 22. A TYPEAHEAD SEARCH BOX function main() { var $input = $('#textInput'), $results = $('#results'); var keyup = Rx.Observable.fromEvent($input, 'keyup') .map(function (e) { return e.target.value; }) .filter(function (text) { return text.length > 2; }) .debounce(750) .distinctUntilChanged(); var searcher = keyup.flatMapLatest(searchWikipedia); searcher.subscribe( function (data) { $results .empty() .append($.map(data[1], function (v) { return $('<li>').text(v); })); }, function (error) { $results .empty() .append($('<li>')) .text('Error:' + error); }); } ➤ What are we doing? 1. we are creating an observable stream from the dom element’s “keyup” event 2. we filter that event data so that we only get values longer than 2 keys 3. we pause for 0.75 s 4. and do all this only if the value has changed 5. use flatMap to pass the input to the http method 6. subscribe to the stream and output the result to the dom
  23. 23. OBSERVABLE AND/OR OPERATIONS // Get elements let weightSliderElem = document.querySelector('#weight-slider'); let weightTextElem = document.querySelector('#weight-text'); let heightSliderElem = document.querySelector('#height-slider'); let heightEditTextElem = document.querySelector('#height-edit-text'); let heightTextElem = document.querySelector('#height-text'); let bmiTextElem = document.querySelector('#bmi-text'); // Observables let weight = Rx.Observable.fromEvent(weightSliderElem, 'input') .map(ev => ev.target.value) .startWith(weightSliderElem.value); let height1 = Rx.Observable.fromEvent(heightSliderElem, 'input') .map(ev => ev.target.value) .startWith(heightSliderElem.value); let height2 = Rx.Observable.fromEvent(heightEditTextElem, 'input') .map(ev => parseInt(ev.target.value)) .startWith(heightEditTextElem.value); let height = height1.merge(height2); let bmi = weight.combineLatest(height, (w,h) => w/(h*h*0.0001)); // Subscriptions weight.subscribe(x => weightTextElem.innerHTML = x); height1.subscribe(x => heightTextElem.innerHTML = x); bmi.subscribe(x => bmiTextElem.innerHTML = x); ➤ What are we doing? 1. We start by creating observable streams from dom events 2. We create the height variable by combining multiple observable streams into a new observable 3. We create a new observable variable by using comblineLatest() method that emits a value ,filtered from the source observables latest emitted values. 4. We then handle the display logic. Code sample from André Staltz
  24. 24. FURTHER READING AND DOCUMENTATION SOURCES➤ Best intro to RxJS in the world: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 ➤ The documentation: http://reactivex.io/documentation/observable.html ➤ Github page: https://github.com/Reactive-Extensions/RxJS ➤ egghead.io: https://egghead.io/technologies/rx ➤ And … google it
  25. 25. QUESTIONS PLS…

×