change detection anno domini 2016

70
@ArturSkowronski CHANGE DETECTION ANNO DOMINI 2016

Upload: artur-skowronski

Post on 13-Apr-2017

181 views

Category:

Engineering


3 download

TRANSCRIPT

@ArturSkowronski

CHANGE DETECTIONANNO DOMINI 2016

ANGULAR MAGICREACT MAGICEMBER MAGIC

Any su�ciently advancedtechnology isindistinguishable frommagic.

- Arthur C. Clarke

IT IS ALL ABOUT STATE...... HOW WE MANAGE IT ...... AND HOW WE RENDER IT

MODEL -> DOM (RENDERING OR PROJECTION)FUNCTION(JSON) => DOM

DOM CHANGES ARE COSTLY

ONCE UPON A TIME...

FACEBOOK 2004

FACEBOOK TODAY

SPA

CLICK ME

IMPERATIVE AS HELL...

7. $("#first-one").css('background-color','green'); 8. $("#second-one").css('background-color','green'); 9. $("#third-one").css('background-color','green');

1. <button id="button">Click Me</button> 2. <div id="first-one"></div> 3. <div id="second-one"></div> 4. <div id="third-one"></div> 5. 6. $( "#button" ).click(function() {

10. }); 11.

TWO-WAY DATA-BINDINGSOBSERVERS/WATCHERS

MUTATOR FUNCTION

8. $scope.colorToGreen = function(){ 9. $scope.colorVar = "green" 10. }

1. <button ng-click="colorToGreen()">Click Me</button> 2. <div ng-style="{'background-color': colorVar}"></div> 3. <div ng-style="{'background-color': colorVar}"></div> 4. <div ng-style="{'background-color': colorVar}"></div> 5. 6. $scope.colorVar = "white" 7.

11.

MAGIC?

DIGEST LOOP & DIRTY CHECKING

EVENTS NOT CONTROLED BY ANGULAR.JS

15. setTimeout(function () { 16. $scope.message = "delayed message"; 17. $scope.$apply(); 18. }, 2000);

3. $scope.message = {} 4. 5. $watchList = [] 6. 7. scope.$watch('name', function(newValue, oldValue) { 8. scope.counter = scope.counter + 1; 9. }); 10. 11. angular.element(element).on(EVENT, function(){

12. $apply(); 13. }, 500)); 14.

19.

OBJECT.OBSERVE()

01.2016OBJECT.OBSERVE()

PROXIES

ZONES

ZONE.JS

MONKEY PATCHING

23. Zone.setInterval() 24. Zone.setTimeout() 25. Zone.alert() 26. Zone.prompt() 27. Zone.requestAnimationFrame() 28. Zone.addEventListener() 29. Zone.removeEventListener() 30. XMLHttpRequest 31.

11. });

12. 13. zone.setTimeout = function(cb, time){ 14. let window = localWindowGlobal; 15. 16. nativeSetTimeout(function(){ 17. angularStuff(); 18. cb(); 19. }, time); 20. 21. } 22.

export function patchMethod(target: any, name: string, patchFn: (delegate: Function, delegateName: string, name: string) => (self: any, args: any[]) => any): Function { let proto = target; while (proto && !proto.hasOwnProperty(name)) { proto = Object.getPrototypeOf(proto); } if (!proto && target[name]) { // somehow we did not find it, but we can see it. This happens on IE for Window properties. proto = target; } const delegateName = zoneSymbol(name); let delegate: Function; if (proto && ! (delegate = proto[delegateName])) { delegate = proto[delegateName] = proto[name]; proto[name] = createNamedFn(name, patchFn(delegate, delegateName, name)); } return delegate; } https://github.com/angular/zone.js/blob/master/lib/common/utils.ts

Jan Matejko (1862)

LEAD ANGULAR EXPERT AFTER ANNOUNCEMENTABOUT MOVING THE PROJECT TO REACT.JS

CLICK ME

26. <div style={style}></div>

15. }); 16. } 17. 18. render() { 19. const style = { 20. background: this.state.color, 21. }; 22. 23. return ( 24. <div> 25. <div style={style}></div>

27. <div style={style}></div> 28. <button style={styles} onClick={this.handleClick}>Click Me</button> 29. </div> 30. ); 31. } 32. } 33.

setState() -> generate whole new DOM

DOM CHANGES ARE COSTLY?

VIRTUALDOM

RECONCILATION (DIFF)

O(N3)1000 x 1000 x 1000

HEURISTIC

...RECONCILE EVERYTHING

9. Remove style color, Add style font-weight - difference

1. renderA: <div /> 2. renderB: <span /> 3. 4. Remove Node <div>, Insert Node <span> - full rerender 5. 6. renderA: <div style="{{color:red}}"/> 7. renderB: <div style="{{fontWeight:bold}}"/> 8.

10.

shouldComponentUpdate()LIGHTWEIGHT AS POSSIBLE

ANGULAR 2 ALSO HAS COMPONENT TREE

DEVELOPERS + ABSTRACTION = LOVE

OVER AND OVER

1. while (op) { 2. var getter = getterFor(op.fieldName); 3. 4. var oldValue = op.value; 5. var newValue = getter(op.context); 6. 7. if (oldValue != newValue) { 8. op.value = newValue; 9. 10. var fn = reconcilationFunctionFor(op); 11. fn(oldValue, newValue)

12. }

12. }

VM + ABSTRACTION = ...

MONOMORPHISM

POLIMORPHICAL STRUCTURE

10. checkWeapon(thor) 11. checkWeapon(cap)

1. function checkWeapon(hero) { 2. console.log(hero.weapon) 3. } 4. 5. // ... 6. 7. var thor = {weapon: 'hammer'} 8. var cap = {weapon: 'shield', citizenship: "America"} 9.

12.

CODE GENERATION FOR RESCUE

...JUST ON THIS SPECIFIC OBJECT

7. if(hammer != this.previousHammer){ 8. this.previousHammer = hammer; 9. this.heroComponent.hammer = hammer; 10. }

1. <hero [weapon]="thor.hammer"></hero> 2. 3. Class Thor_ChangeDetector { 4. detectChanges() { 5. var thor = obj.thor; 6. var hammer = thor.hammer

11. } 12. } 13.

3-10X FASTER

IMMUTABILITYNEWVALUE == OLDVALUE? :(

NEW OBJECT

9. x === y //false

1. var thor = {weapon: "hammer"} 2. var newThor = thor; 3. newThor.weapon = "shield" 4. x === y // true 5. 6. var ImmutableHero = Immutable.Record({ weapon: null }); 7. var thor = new ImmutableHero({ weapon: 'hammer'}); 8. var newThor = hero.set('weapon', 'shield');

10.

TOOLINGOBJECT.ASSIGN, IMMUTABLE.JS

ANGULAR METADATA

1. @Component({changeDetection:ChangeDetectionStrategy.OnPush}) 2. class ImmutableHammerCmp { 3. hammer:Hammer; 4. } 5.

PureRenderMixin

USE SHOULD COMPONENT UPDATE

5. this.shouldComponentUpdate = mx.shouldComponentUpdate.bind(this);

1. import mx from 'react-addons-pure-render-mixin'; 2. class FooComponent extends React.Component { 3. constructor(props) { 4. super(props);

6. } 7. 8. render() { 9. return <div className={this.props.className}>foo</div>; 10. } 11. } 12.

LAST BUT NOT LEAST... RX

DEFINE OBSERVABLES

1. @Component({selector:'weapon'}) 2. class ObservableHeroCmp { 3. weapon:ObservableWeapons ; 4. } 5.

WRAPPING UP

THANK YOUAND WAITING FOR QUESTIONS