SlideShare ist ein Scribd-Unternehmen logo
1 von 102
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!

Weitere ähnliche Inhalte

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

High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
DjangoCon2008
 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1
DjangoCon2008
 

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

Capybara with Rspec
Capybara with RspecCapybara with Rspec
Capybara with Rspec
 
Advanced Cartography for the Web
Advanced Cartography for the WebAdvanced Cartography for the Web
Advanced Cartography for the Web
 
Webrender 1.0
Webrender 1.0Webrender 1.0
Webrender 1.0
 
Drupal front-end performance
Drupal front-end performance Drupal front-end performance
Drupal front-end performance
 
Streaming SQL for Data Engineers: The Next Big Thing? With Yaroslav Tkachenko...
Streaming SQL for Data Engineers: The Next Big Thing? With Yaroslav Tkachenko...Streaming SQL for Data Engineers: The Next Big Thing? With Yaroslav Tkachenko...
Streaming SQL for Data Engineers: The Next Big Thing? With Yaroslav Tkachenko...
 
Streaming SQL for Data Engineers: The Next Big Thing?
Streaming SQL for Data Engineers: The Next Big Thing?Streaming SQL for Data Engineers: The Next Big Thing?
Streaming SQL for Data Engineers: The Next Big Thing?
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1
 
JavascriptMVC: Another choice of web framework
JavascriptMVC: Another choice of web frameworkJavascriptMVC: Another choice of web framework
JavascriptMVC: Another choice of web framework
 
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Design Summit - UI Roadmap - Dan Clarizio, Martin PovolnyDesign Summit - UI Roadmap - Dan Clarizio, Martin Povolny
Design Summit - UI Roadmap - Dan Clarizio, Martin Povolny
 
Cache the directionality of the element
Cache the directionality of the elementCache the directionality of the element
Cache the directionality of the element
 
Apache Pinot Meetup Sept02, 2020
Apache Pinot Meetup Sept02, 2020Apache Pinot Meetup Sept02, 2020
Apache Pinot Meetup Sept02, 2020
 
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
 
Sprint 58
Sprint 58Sprint 58
Sprint 58
 
Front end performance tip
Front end performance tipFront end performance tip
Front end performance tip
 
Modular Web Applications With Netzke
Modular Web Applications With NetzkeModular Web Applications With Netzke
Modular Web Applications With Netzke
 
ENIB 2015-2016 - CAI Web - S01E01- Côté navigateur 3/3 - Web components avec ...
ENIB 2015-2016 - CAI Web - S01E01- Côté navigateur 3/3 - Web components avec ...ENIB 2015-2016 - CAI Web - S01E01- Côté navigateur 3/3 - Web components avec ...
ENIB 2015-2016 - CAI Web - S01E01- Côté navigateur 3/3 - Web components avec ...
 
Everything is Awesome - Cutting the Corners off the Web
Everything is Awesome - Cutting the Corners off the WebEverything is Awesome - Cutting the Corners off the Web
Everything is Awesome - Cutting the Corners off the Web
 
Awesome html with ujs, jQuery and coffeescript
Awesome html with ujs, jQuery and coffeescriptAwesome html with ujs, jQuery and coffeescript
Awesome html with ujs, jQuery and coffeescript
 
CSSO – compress CSS (english version)
CSSO – compress CSS (english version)CSSO – compress CSS (english version)
CSSO – compress CSS (english version)
 

Mehr von Sigma Software

Mehr von Sigma Software (20)

Fast is Best. Using .NET MinimalAPIs
Fast is Best. Using .NET MinimalAPIsFast is Best. Using .NET MinimalAPIs
Fast is Best. Using .NET MinimalAPIs
 
"Are you developing or declining? Don't become an IT-dinosaur"
"Are you developing or declining? Don't become an IT-dinosaur""Are you developing or declining? Don't become an IT-dinosaur"
"Are you developing or declining? Don't become an IT-dinosaur"
 
Michael Smolin, "Decrypting customer's cultural code"
Michael Smolin, "Decrypting customer's cultural code"Michael Smolin, "Decrypting customer's cultural code"
Michael Smolin, "Decrypting customer's cultural code"
 
Max Kunytsia, “Why is continuous product discovery better than continuous del...
Max Kunytsia, “Why is continuous product discovery better than continuous del...Max Kunytsia, “Why is continuous product discovery better than continuous del...
Max Kunytsia, “Why is continuous product discovery better than continuous del...
 
Marcelino Moreno, "Product Management Mindset"
Marcelino Moreno, "Product Management Mindset"Marcelino Moreno, "Product Management Mindset"
Marcelino Moreno, "Product Management Mindset"
 
Andrii Pastushok, "Product Discovery in Outsourcing - What, When, and How"
Andrii Pastushok, "Product Discovery in Outsourcing - What, When, and How"Andrii Pastushok, "Product Discovery in Outsourcing - What, When, and How"
Andrii Pastushok, "Product Discovery in Outsourcing - What, When, and How"
 
Elena Turkenych “BA vs PM: Who' the right person, for the right job, with the...
Elena Turkenych “BA vs PM: Who' the right person, for the right job, with the...Elena Turkenych “BA vs PM: Who' the right person, for the right job, with the...
Elena Turkenych “BA vs PM: Who' the right person, for the right job, with the...
 
Eleonora Budanova “BA+PM+DEV team: how to build the synergy”
Eleonora Budanova “BA+PM+DEV team: how to build the synergy”Eleonora Budanova “BA+PM+DEV team: how to build the synergy”
Eleonora Budanova “BA+PM+DEV team: how to build the synergy”
 
Stoyan Atanasov “How crucial is the BA role in an IT Project"
Stoyan Atanasov “How crucial is the BA role in an IT Project"Stoyan Atanasov “How crucial is the BA role in an IT Project"
Stoyan Atanasov “How crucial is the BA role in an IT Project"
 
Olexandra Kovalyova, "Equivalence Partitioning, Boundary Values ​​Analysis, C...
Olexandra Kovalyova, "Equivalence Partitioning, Boundary Values ​​Analysis, C...Olexandra Kovalyova, "Equivalence Partitioning, Boundary Values ​​Analysis, C...
Olexandra Kovalyova, "Equivalence Partitioning, Boundary Values ​​Analysis, C...
 
Yana Lysa — "Decision Tables, State-Transition testing, Pairwase Testing"
Yana Lysa — "Decision Tables, State-Transition testing, Pairwase Testing"Yana Lysa — "Decision Tables, State-Transition testing, Pairwase Testing"
Yana Lysa — "Decision Tables, State-Transition testing, Pairwase Testing"
 
VOLVO x HACK SPRINT
VOLVO x HACK SPRINTVOLVO x HACK SPRINT
VOLVO x HACK SPRINT
 
Business digitalization trends and challenges
Business digitalization trends and challengesBusiness digitalization trends and challenges
Business digitalization trends and challenges
 
Дмитро Терещенко, "How to secure your application with Secure SDLC"
Дмитро Терещенко, "How to secure your application with Secure SDLC"Дмитро Терещенко, "How to secure your application with Secure SDLC"
Дмитро Терещенко, "How to secure your application with Secure SDLC"
 
Яна Лиса, “Ефективні методи написання хороших мануальних тестових сценаріїв”
Яна Лиса, “Ефективні методи написання хороших мануальних тестових сценаріїв”Яна Лиса, “Ефективні методи написання хороших мануальних тестових сценаріїв”
Яна Лиса, “Ефективні методи написання хороших мануальних тестових сценаріїв”
 
Тетяна Осетрова, “Модель зрілості розподіленної проектної команди”
Тетяна Осетрова, “Модель зрілості розподіленної проектної команди”Тетяна Осетрова, “Модель зрілості розподіленної проектної команди”
Тетяна Осетрова, “Модель зрілості розподіленної проектної команди”
 
Training solutions and content creation
Training solutions and content creationTraining solutions and content creation
Training solutions and content creation
 
False news - false truth: tips & tricks how to avoid them
False news - false truth: tips & tricks how to avoid themFalse news - false truth: tips & tricks how to avoid them
False news - false truth: tips & tricks how to avoid them
 
Анна Бойко, "Хороший контракт vs очікування клієнтів. Що вбереже вас, якщо вд...
Анна Бойко, "Хороший контракт vs очікування клієнтів. Що вбереже вас, якщо вд...Анна Бойко, "Хороший контракт vs очікування клієнтів. Що вбереже вас, якщо вд...
Анна Бойко, "Хороший контракт vs очікування клієнтів. Що вбереже вас, якщо вд...
 
Дмитрий Лапшин, "The importance of TEX and Internal Quality. How explain and ...
Дмитрий Лапшин, "The importance of TEX and Internal Quality. How explain and ...Дмитрий Лапшин, "The importance of TEX and Internal Quality. How explain and ...
Дмитрий Лапшин, "The importance of TEX and Internal Quality. How explain and ...
 

Kürzlich hochgeladen

Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 

Kürzlich hochgeladen (20)

WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 

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