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 Koretskyi "Why are Angular and React so fast?"

188 views

Published on

Very few developers have the need to write super optimized code. In application development, we tend to favor readability over optimization. But that’s not the case with frameworks. Developers who use frameworks expect them to run as fast as possible. In fact, speed is often a defining characteristic when choosing a framework. There are techniques that make code run faster. You’ve probably heard about linked lists, monomorphism, and bitmasks, right? Maybe you've even used some. Well, you can find all these and a bunch of other interesting approaches in the sources of most popular JS frameworks.

Over the past year, I’ve seen a lot while reverse-engineering Angular and React. In this talk, I want to share my findings with you. Some of you may end up applying them at work. And others, who knows, may even end up writing the next big framework.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Max Koretskyi "Why are Angular and React so fast?"

  1. 1. Why Angular and React are so fast? Max Koretskyi aka Wizard Developer Advocate
  2. 2. 2015 20162014 2017 2018 A failed startup that made me learn to program and gave broad programming experience SO activity that build my knowledge base and created a foundation for blogging Angular In Depth that helped me build strong community and establish reputation as an Angular expert Public speaking that helped me meet awesome people and become GDE and MVP Developer Advocate job that allows me to to develop programming and marketing skills at the same time My 5 years in IT
  3. 3.  maxkoretskyi.com/connecting-the-dots  https://youtu.be/fT9CZ2QZx5A Find out more at
  4. 4. Benedikt Meurer, V8 optimizations lead engineer Alex Rickabught, Angular core team Dan Ambramov, React core team Monomorphism Bit fields & Bit masks Bloom filters Kudos to Optimization techniques in Angular and React
  5. 5. We use one type for all View nodes so that property access in loops stay monomorphic! Misko Hevery, technical lead of Angular Angular sources comments
  6. 6. Fiber node … shares the same hidden class. Never add fields outside of construction in `ReactFiber` Contributing To React Fiber guidelines Sebastian Markbåge, technical lead of React
  7. 7. • What is a fiber node in React & a view node in Angular? • What is hidden class and why is it shared by fiber and view nodes? • What is monomophic property access and why is it important? Questions we need to answer
  8. 8. Representing a template in Angular @Component({ template: ` <h1>The title is: {{title}}</h1> <h2>My hero is: {{hero}}</h2> ` }) export class AppComponent { title = 'Tour of Heroes'; hero = 'Windstorm'; } Type: h1 Type: h2 View Nodes bindings: { text: "Tour of Heroes" } bindings: { text: " 'Windstorm" }
  9. 9. Representing a template in React class App extends Component { state = { title: 'Tour of Heroes', hero: 'Windstorm' }; render() { return ( [ <h1>The title is: {this.state.title}</h1>, <h2>My hero is: {this.state.hero}</h2> ] ) } } Type: h1 Type: h2 props: { children: "Tour of Heroes" } props: { children: " Windstorm " } Fiber Nodes
  10. 10. Fiber and View nodes are used a lot when processing changes properties could easily be accessed over 10 000* times function updateNode(node, …) { let value = node.property; } *100 components x 10 elements x 10 function calls
  11. 11. Locating value of an object's property in memory is a complicated process
  12. 12. let object = { x: 5, y: 6 }; JSObject 5 6 Property information Offset: 0 [[Writable]]: true [[Enumerable]]: true [[Configurable]]: true Shape 'x' 'y' Property information Offset: 1 [[Writable]]: true [[Enumerable]]: true [[Configurable]]: true Shapes aka Hidden Class (Maps in V8)
  13. 13. 5 6 JSObject a Property information Shape 'x' 'y' Property information JSObject b 7 8 let a = { x: 5, y: 6 }; let b = { x: 7, y: 8 }; Shapes help reduce memory footprint
  14. 14. let a = { x: 5, y: 6 } let b = { x: 7, y: 8 } b.z = 9; b.y = 10; JSObject a 5 6 Shape 'x' 'y' JSObject b 7 8 Shape 'z' Shape 'y' 9 10 Transition chains
  15. 15. Inline Caching (IC) to the rescue
  16. 16. Monomorphic property access getX(a); getX(b); getX(c); function getX(o) { return o.x; } let a = { x: 5, y: 6 }; let b = { x: 7, y: 8 }; let b = { x: 7, y: 8 }; a function only saw one type of a shape
  17. 17. Polymorphic property access getX(a); getX(b); getX(c); getX(D); function getX(o) { return o.x; } let a = {x: 5, y: 6}; let b = {y: 7, x: 8}; // different order let b = {y: 7, x: 8, z: 5}; // new properties let d = Object.create({}, {}; // different prototype a function only saw up to 4 different types of a shape
  18. 18. Megamorphic property access Monomorphic prop access maybe up to 100 times faster than megamorphic. a function saw more than 4 different types of a shape
  19. 19. Frameworks enforce the same shape (hidden class) for fiber and view nodes to enable monomorphic property access
  20. 20. Template node types Fiber node (React) Template element View node (Angular) HostComponent HTMLElementNode TypeElement HostText HTMLTextNode TypeText FunctionComponent, ClassComponent Component Component
  21. 21. type Element { fieldA; fieldB; } type Text { fieldC; field; } type Component { fieldE; fieldF; } Property access is not monormophic type Node { tag: nodeType; fieldA | null; fieldB | null; fieldC | null; fieldD | null; fieldE | null; fieldF | null; } Property access is monormophic
  22. 22. function beginWork(fiberNode, ...) { ... switch (fiberNode.tag) { case FunctionalComponent: {...} case ClassComponent: {...} case HostComponent: return updateHostComponent(fiberNode, ...); case ... Branching by node type in React
  23. 23. Bit fields (vector) & Bit masks
  24. 24. Bit field is just an array of bits let effectTag = 0b01010001; // 81 0 1 0 1 0 0 0 1
  25. 25. Side effects in React fiber are encoded using bit fields 0 1 0 1 0 1 0 0 Placement Update
  26. 26. Effects in React Fiber architecture • Render phase • Process changes from setState • Update props on child elements • Call lifecycle methods (shouldComponentUpdate etc.) The result of the phase is a tree of fiber nodes marked with side-effects. • Commit phase (apply effects) • Update DOM • Call lifecycle methods (componentDidUpdate etc.) • Update refs
  27. 27. Before render phase: After render phase: 4..toString(2) = 100 type: 'span' effectTag: 0 type: 'span' effectTag: 4 const effectTags = { Placement = : 0b000000000010; Update : 0b000000000100; PlacementAndUpdate : 0b000000000110; ... }
  28. 28. let effectTag = 0b00000000; 0 0 0 0 0 0 0 0 effectTag = effectTag | effectTags.Update; 0 0 0 0 0 1 0 0 isUpdateEffectSet = !! (effectTag & effectTags.Update); Write with bitwise OR Define bitfield Check with bitwise AND
  29. 29. Branching by effect in React function updateHostEffects(fiberNode) { ... const effectTag = fiberNode.effectTag; if (effectTag & effectTags.Placement) { ... } if (effectTag & effectTags.PlacementAndUpdate) { ... } if (effectTag & effectTags.Update) { ... } ... }
  30. 30. Encoding objects in bit fields let user = { first: true, group: 20, sortKey: 347843 }; allocations in memory for: • a standard JS object • 3 strings for the keys • 3 values stored in the keys
  31. 31. Encoding objects in bit fields Field Restrictions on values Bits required sortKey less than 1M 20 (220 > 1M) group less than 50 6 (26 = 64) first boolean 1 00000 0 000000 0000000000000000000 sortKeygroupfirst 32 bits
  32. 32. Encoding objects in bit fields let user = 0x 05454ec3; let user = 0b 00000 1 010100 001010100111011000011; let user = { first: true, group: 20, sortKey: 347843 }; Field Decimal Binary sortKey 347843 001010100111011000011 group 20 010100 first true 1
  33. 33. Why bother?
  34. 34. • millions of allocations of keys, objects and values • a ton of GC (garbage collection) cleanup after each iteration • larger and fragmented memory usage 1 million of objects require VS • one typed array for one million 32-integer values • alsmot zero garbage collection • smaller and contiguous memory usage. Regular JS object Encoded in a bitfield
  35. 35. Bloom filters is element in the set? DEFINITELY NO MAYBE 100% probability varying probability data structure that answers the question
  36. 36. 0 1 0 0 0 0 1 0 Is element in a set? Is bits [n1,n2…n] set? Each element is encoded in a bit field let value = "Jonh"; calculateBit1Number(value); // 2 calculateBit2Number(value); // 7
  37. 37. John - 2 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 Using bloom filter for string values Anna – 1 Tom - 4 [ "John", "Anna", "Tom" ] let calculateBit1Value = (value) => value.charCodeAt(0) % 8
  38. 38. Why "yes" is not guaranteed?
  39. 39. Anna – 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 collisions Tom - 4 John - 2 Jane - 2 Less slots, more collisions
  40. 40. How to increase probability of "Yes"?
  41. 41. Anna – 1, 6 0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 0 no collisionsTom – 4, 7 John – 2, 7 Jane – 2, 1 More slots, less collisions
  42. 42. Where does Angular use this? Dependency Injection mechanism
  43. 43. ServiceA ServiceB ServiceC constructor( ServiceA ) {} Injector ServiceD
  44. 44. Hierarchical injectors Dashboard component Widget component SiteAnalytics component WidgetManager Injector Injector WidgetManager Injector Is here? no – go up Is here? no – go up Is here? yes – resolve
  45. 45. Bloom filters Injector Dashboard component Widget component SiteAnalytics component WidgetManager WidgetManager Injector Is here? no – go up Is here? no – go up resolve Injector Bloom filter Bloom filter Bloom filter Is here? maybe – chec injector
  46. 46. Ask me anything
  47. 47. Angular In Depth conference Kyiv, 15th of June
  48. 48. Follow me to learn fundamentals @maxim_koretskyi maxkoretskyi maxkoretskyi.com

×