Performance optimization of Web application based on project experience
by Alina Sinyavskaya and Telman Agababov Front-End developers at Sigma Software 2
About Project 3
Project requirements 4
Project structure data validation data bindings business logic 5
Performance 6
Problems investigation scripting angular execution 7
AngularJS Optimization 8
● each variable in $scope is a watcher ● $digest is called on every change ● second $digest is called when a change is found AngularJS optimization 9
AngularJS optimization ● Minimize $digest calls ● Minimize watchers number 10
AngularJS optimization Optimize ng-repeat <div ng-repeat="item in itemsList"> {{item.name}} </div> <div ng-repeat="item in itemsList track by item.id"> {{item.name}} </div> 11
AngularJS optimization Optimize bindings <div> <span>{{staticValue}}}</span> </div> <div> <span>{{:: staticValue}}</span> </div> 12
AngularJS optimization Optimize watchers number 13 <section ng-if="isSectionAvailable"> <main>{{ sectionContent }}</main> </section> <section ng-show="isSectionActive"> <main>{{ sectionContent }}</main> </section>
AngularJS optimization $digest dirty checking optimization 14 <section> <div>{{ sectionInfo }}</div> </section> <section> <div>{{ getSectionInfo() }}</div> </section>
AngularJS optimization $digest dirty checking optimization 15 <div ng-repeat="item in orderedItems track by item.id"> {{item.name}} </div> <div ng-repeat="item in itemsList | orderByName track by item.id"> {{item.name}} </div>
AngularJS optimization $digest scope minimization 16 <dialog-component x="options.x" y="options.y" title="options.title"> </dialog-component> <dialog-component options="options"> </dialog-component>
AngularJS optimization manual $digest invocation 17 model changed$digest for synchronization
AngularJS optimization $digest calls optimization 18 $scope.$eval(); $scope.$apply(); $timeout( function() { }, delay); $interval( function() { }, delay); $rootScope.value = newValue; $parent.value = newValue;
AngularJS optimization $timeout/$interval scope reduction 19 var intervalInstance = $interval(function() { updateData(); $scope.$digest(); }, delay, false);
AngularJS optimization $apply scope reduction 20 // from view $scope.$digest(); // safe option $timeout(function() { $scope.$digest(); }, 0, false); // root scope $scope.$applyAsync();
AngularJS optimization $scope reduction ● split into components ● child controllers ● ng-if / ng-repeat 21
AngularJS optimization $digest cycles remove ● update values directly in DOM element 22
AngularJS performance check $watchers calculation 23 function getElementWatchers(element) { // current element watchers var watchersNumber = element.data().$scope.$$watchers.length; // child watchers angular.forEach(element.children(), function (childElement) { watchersNumber += getElementWatchers(angular.element(childElement)); }); return watchersNumber; } console.log("watchers count: ", getElementWatchers($("custom-component")));
AngularJS performance results results 24 $digest 60-70% $digest 6-8%
Animations... 25
IE11 26
IE11 tools 27
IE11 optimization 28
IE11 optimization 29
IE11 optimization 30
IE11 optimization 31
IE11 optimization ● Create a new layout 32 .new-layout-transform { transform: translateZ(0); /* any CSS 3d option;*/ } .new-layout-will-change { will-change: transform; }
IE11 optimization 33
IE11 optimization ● Reduce reflow 34
IE11 optimization ● Reduce reflow 35 elementA.className = "a-style"; var heightA = elementA.offsetHeight; // layout is needed elementB.className = "b-style"; // invalidates the layout var heightB = elementB.offsetHeight; // layout is needed again elementA.className = "a-style"; elementB.className = "b-style"; var heightA = elementA.offsetHeight; // layout is needed and calculated var heightB = elementB.offsetHeight; // layout is up-to-date (no work)
IE11 optimization ● Reduce re-layouts 36
IE11 optimization ● Cache DOM accessing results 37 $("element") .css("color", "#AA0000") .css("background-color", "#00ff00") .width(200) $("element").css("color", "#AA0000"); $("element").css("background-color", "#00ff00"); $("element").width(200);
IE11 optimization ● Gather changes in DOM (requestAnimationFrame) 38
React in AngularJS ● ng-react 39 <react-component props=”componentOptions” name="ComponentName"> </react-component>
IE11 performance results results 40 3200 watchers 2 - 5 FPS 40 - 60 FPS 600 watchers
React performance 41
React problems $digest / render cycles 42 onUpdated
React optimization reduce $digest / render cycles 43 onUpdated onUpdatedupdate update
React optimization 44 shouldComponentUpdate
React optimization remove unnecessary re-renderings 45 shouldComponentUpdate: function (nextProps, nextState) { return this.state.id !== nextState.id || this.state.value !== nextState.value || this.props.isActive !== nextProps.isActive || this.props.styleOptions.color !== nextProps.styleOptions.color; } shouldComponentUpdate: function () { return this.isMounted(); }
React optimization re-rendering 46 ● array items re-rendering ● scope size re-rendering ● frame rendering optimization key={item.id} small components requestAnimationFrame
React optimization results 47 Scripting x4 Rendering x1.5 Painting x1.5
Desktop performance optimization challenge completed
Tablet support requested: iOS & Android ● iPad 2/3/4/Air 2/Pro ● Samsung/Lenovo 49
Touch gestures: ● scroll ● swipe ● drag&drop ● pinch & zoom 50
51
Diving into GPU animations 52
How painting works 53
How painting works Reflow Repaint GPU Display 54
How to optimize? To optimize the painting, the browser has to ensure that the animated CSS property: ● does not affect the document’s flow, ● does not depend on the document’s flow, ● does not cause a repaint. 55
How optimization works: compositing layers 56
How optimization works Reflow Repaint GPU Display 57
Optimization pros ● Quick smooth animation with subpixel precision ● No binding to the CPU 58
BUT... 59
picture TBD MEMORY 60
How much memory is required? 300x300, #FF0000 300 x 300 x 4 = 360,000 Bytes! 61
Compositing reasons ● 3D transformations: translate3d, translateZ, etc. ● <video>, <canvas>, <iframe> elements ● transform and opacity animations ● backface-visibility: hidden ● CSS filters ● will-change ● -webkit-overflow-scrolling: touch ● elements that overlap composited layers 62
View layers information in Chrome 63
1 64
2 65
3 66
Let’s check... 67
No compositing layers #a { left: 50px; top: 50px; z-index: 2; animation: move 1s linear infinite alternate; background: red; } @keyframes move { from { left: 30px; } to { left: 100px; } } 68
69
70
Let’s create compositing layer... #a { left: 50px; top: 50px; z-index: 2; animation: move 1s linear infinite alternate; background: red; } @keyframes move { from { transform: translateX(0); } to { transform: translateX(70px); } } 71
72
73
74
75
What about iPad? ● iPad Air 2 / iPad Pro: 2 GB RAM ● iPad 4 / iPad 3: 1 GB RAM ● iPad 2: 512 MB RAM 76
Let’s create some example 77
Demo appz-index will-change will-change will-change JS timer CSS animation with opacity iframe -webkit-overflow- scrolling: touch child iframe transform: scale 78
79
iPad Air 2 with iOS 10 Crashes after 25 seconds of active zooming 80
View layers information in Safari 81
82
83
Let’s optimize our application 84
Let’s optimize our application 1. remove transform: scale 2. remove 3d transformations 3. remove will-change property 4. -webkit-overflow-scrolling: touch -> -webkit-overflow-scrolling: auto 5. minimize assets 6. remove child iframe 85
86
Works stable! 87
88
iPad Air 2 with iOS 11 Crashes after 10 seconds of active zooming! 89
Memory profiling TODO screenshot 90
Viewing compositing borders TODO screenshot 91
92
93
Compositing borders ● Blue: page tiles. ● Green: has a compositing layer with its own painted content. ● Orange: has a backing store and extend partially offscreen, so it’s converted to tiled layers. ● Pale Blue: clipped layer. ● Light Blue and Dark Blue: the image is being mapped directly into the backing store without having to be painted. ● Yellow: container layers have blue borders with a yellow inner border. ● Bright Pink: elements with backdrop filters. 94
Compositing borders ● Blue: page tiles. ● Green: has a compositing layer with its own painted content. ● Orange: has a backing store and extend partially offscreen, so it’s converted to tiled layers. ● Pale Blue: clipped layer. ● Light Blue and Dark Blue: the image is being mapped directly into the backing store without having to be painted. ● Yellow: container layers have blue borders with a yellow inner border. ● Bright Pink: elements with backdrop filters. 95
96
97
What can we do? ● remove all iframes or ● leave iframes but remove all compositing layers 98
99
Reported issues ● Webkit bugzilla - Status: NEW, ~ 22 similar issues ● Apple bugzilla - Status: NEW. Reproduced on Apple website. 100
Lessons learnt ● Be ready to support new devices ● Be careful with compositing layers especially on iOS devices ● Pay attention to your assets ● Use iframes only in case of necessity ● Perform regression testing when new OS is installed 101
Thanks for your attention!

Performance optimization in JS. Based on project experience, Алина Синявская и Тельман Агабабов