JavaScript Front-End Performance Optimizations
Northeast JavaScript Conference
LOVE2DEV.COM
My BioMicrosoft MVPASP Insider Edge User AgentWeb Developer 25 yearsAuthor & Speaker
@ChrisLoveLove2Dev.com
Source Codehttp://
GitHub.com/docluv
Slide Deck http://slideshare.net/docluv/presentations
10 Days to HTML5 Fitness
http://bit.ly/2ctJMiU
Annoying???
LOVE2DEV.COM
"Also take a step back for a minute and consider the intent of this change: a faster web is great for everyone, but especially for users. Lots of websites have demonstrated that speeding up the user experience results in more usage. So speeding up your website isn’t just something that can affect your search rankings–it’s a fantastic idea for your users.“
http://bit.ly/SPPB4k
Matt Cutts
LOVE2DEV.COM
GOALSWeb Trends & Some HistoryFront-End Architecture Best PracticesCoding SyntaxNavigation & Performance Timing APIBuild & Deploy
Web Trends & History
LOVE2DEV.COM
6 Years of JS Weight Gain
The Reach of JavaScript ExpandedWeb Applications/SPAs
HTML5 GamesBasic Web Pages
JavaScript Execution Speed
DOM InteractionsAccelerated Graphics
Page Load Time
Conference Sponsor Sites Performance
LOVE2DEV.COM
Conference Sponsor Sites Averages
LOVE2DEV.COM
•Document Complete 6.94s• Fully Loaded 8.7s• Page Weight 2.8MB• JS Weight 788kb
Web Sites Are Obese & Out of Shape
http://httpArchive.org as of 5/15/2016
117 File Requests – 2.4+MB23 JavaScript Files - 401KB7.1 CSS Files – 74KB56 Images – 1.577MB36 TCP Connections19 Domains48% Cacheable
Is JavaScript the Problem?
YUI
TotalSize (k)
NumberElements
CSSRules
ImageFiles
ScriptLines (F)
ScriptLibraries
Site #1 3,697 1,504 1,392 41 77,768
Site #2 2,278 1,100 5,325 29 39,183
Site #3 1,061 2,673 1,105 66 12,643
Site #4 1,812 4,252 1,672 12 10,284
Site #5 1,372 900 3,902 6 38,269
jQuery Prototype ExtJS OtherScriptaculous
YUI
TotalSize (k)
NumberElements
CSSRules
ImageFiles
ScriptLines (F)
ScriptLibraries
Site #1 3,697 1,504 1,392 41 77,768
Site #2 2,278 1,100 5,325 29 39,183
Site #3 1,061 2,673 1,105 66 12,643
Site #4 1,812 4,252 1,672 12 10,284
Site #5 1,372 900 3,902 6 38,269
jQuery Prototype ExtJS OtherScriptaculous
Fastest
YUI
TotalSize (k)
NumberElements
CSSRules
ImageFiles
ScriptLines (F)
ScriptLibraries
Site #1 3,697 1,504 1,392 41 77,768
Site #2 2,278 1,100 5,325 29 39,183
Site #3 1,061 2,673 1,105 66 12,643
Site #4 1,812 4,252 1,672 12 10,284
Site #5 1,372 900 3,902 6 38,269
jQuery Prototype ExtJS OtherScriptaculous
Slowest
Is JavaScript the Problem?• Bytes Must Be Downloaded• Bytes Cost Real Money• 25% of US Exceeds Monthly Bandwidth
• Bytes Take Time• Scripts Must Be Evaluated• Libraries Can Overwrite Native APIs or Don’t Use Native APIs
LOVE2DEV.COM
Don’t Guess•Use Profiling Tools• Establish Benchmarks• < 1s Desktop/Broadband• < 3s Mobile/GPRS
• Test On Real Devices Against ‘Real Site’• Have a 2G Day
• Apply Scientific Method to Solve Problems
LOVE2DEV.COM
Establish a Performance Culture
• Make Perforamance a 1st Class Citizen of Your Team• Include Developers, Architects, QA &
Stakeholders• Etsy Quarterly Performance Reports
• https://codeascraft.com/2016/04/28/q1-2016-site-performance-report/
• Designing For Performance• http://amzn.to/2d30GRy
Don’t Assume Broadband
What Does Your Site Cost?
http://whatdoesmysitecost.com
Power Consumption
Real & Perceived Performance
Architecture Best Practices
LOVE2DEV.COM
Place Script References At The Bottom• SCRIPT is a Blocking Action• Allow Browser to Render As Much As Possible Before Evaluating & Executing Scripts
JS Parse & Execution Time• Scripts Must Be Downloaded• Scripts Must Be Evaluated•Majority of Traffic from Mobile Class Devices• Lower Powered CPU• Less Memory
• Etsy Tool• https://timkadlec.com/2014/09/js-parse-and-execution-time/
Best Practice• Ask If Script/Library/Framework Is Really Needed• Are Their Alternatives?• Strive to Use Libraries Components That Do What Needs to be Done
Best Practice – Libraries & Frameworks•Use A Single Library• Keep Library Up To Date• Avoid Duplicate References• Avoid Duplicate Versions
Avoid Duplicate Code<html><head><title>Test</title></head><body>…<script src="jquery.js" … ></script><script src="myscript.js" … ></script> <script src="navigation.js" … ></script><script src="jquery.js" … ></script></body>
</html>
Avoid Duplicate Code
52%of the pages on the web
have duplicate code
Standardize on Single Library/Framework<script src="jquery.js" … ></script><script src="prototype.js" … ></script><script src="dojo.js" … ></script><script src="animater.js" … ></script><script src="extjs.js" … ></script><script src="yahooui.js" … ></script><script src="mochikit.js" … ></script><script src="lightbox.js" … ></script><script src="jslibs.js" … ></script><script src=“gsel.js" … ></script>…
ASP.NET Web Client Library
Prototype
jQuery/jQueryUI
Ember
Angular
React
Ask If It Is Needed• Avoid Framework Archeology•Don’t Use a Library/Framework to be Cool • Resume Driven Development
• Remember the Goal is to Make the Customer Happy• They Pay the Bills!
•Majority of Pages/Sites are Still Read-Only
Use Async & Defer• Allows Browser to Finish Rendering Cycle•Use When Script Order is not important•Use When Script is not needed to render
Audit 3rd Parties
3rd Parties•Often Added By Marketing Departments•Use of Tag Managers•Many Are Not Used by Stakeholders•Not Part of Application/Site Q/A•Not Managed By DevOps•Not Held to SLA
LOVE2DEV.COM
3rd Parties• You Are Outsourcing Control Of Your Business To A Supplier You Have Little or No Control• They Can & Do Have A Big Impact On Your Brand Image and Engagment
LOVE2DEV.COM
DOM Interactions• Built In DOM Methods More Efficient• Avoid Type Conversion• Avoid DOM Chatiness
LOVE2DEV.COM
DOM Methods More Efficient• querySelector• querySelectorAll• firstElementChild• nextElementSibling• previousElementSibling• lastElementChild• childElementCount
LOVE2DEV.COM
function InsertUsername(){
document.getElementById('user').innerHTML = userName;}
User .innerHTML to Construct Your PageUse DOM Efficiently
function InsertUsername(){
document.getElementById('user').innerHTML = userName;}
User .innerHTML to Construct Your PageUse DOM Efficiently
function BuildUI() { var elm = document.getElementById('ui'); var contents = BuildTitle() + BuildBody() + BuildFooter(); elm.innerHTML = contents;}
Batch Markup ChangesUse DOM Efficiently
function BuildUI() { var elm = document.getElementById('ui'); var contents = BuildTitle() + BuildBody() + BuildFooter(); elm.innerHTML = contents;}
Batch Markup ChangesUse DOM Efficiently
function BuildUI() { var elm = document.getElementById('ui'); var contents = BuildTitle() + BuildBody() + BuildFooter(); elm.innerHTML = contents;}
Batch Markup ChangesUse DOM Efficiently
function BuildUI() { var elm = document.getElementById('ui'); var contents = BuildTitle() + BuildBody() + BuildFooter(); elm.innerHTML = contents;}
Batch Markup ChangesUse DOM Efficiently
Small Healthy DOM
LOVE2DEV.COM
Use DOM Methods to Create Collections
LOVE2DEV.COM
Use DOM Selectors Collection Access
LOVE2DEV.COM
Avoid DOM Type Conversion
Avoid DOM Chatiness
Performance•UI Responsiveness• Identify CPU Intensive Code• Identify Frame Rate Issues
• JavaScript Profiling• Identify Code Bottlenecks
LOVE2DEV.COM
Memory Profiling
Memory Profiling• Timeline to Identify Memory Pressure Issues• Track Down Memory Leaks
LOVE2DEV.COM
Memory Utilization
Memory Leaks
Memory Leaks
Memory Leaks
Array Best Practices• Pre-Allocate• Keep Array Type Consistent•Use Typed Arrays• Keep Arrays Dense• Enumerate Efficiently
LOVE2DEV.COM
Use Typed Arrays
LOVE2DEV.COM
Sparse vs Dense Arrays• Arrays are Sparse, they have holes in them• A map from indices to values
LOVE2DEV.COM
Sparse vs Dense Arraysvar a = new Array(3);
a [ , , ];
a.length === 3 a[0] === undefined
a.map(function (x, i) { return i }) === [ , , ]
LOVE2DEV.COM
Sparse vs Dense Arrays• Array(undefined, undefined, undefined)
• a.map(function (x, i) { return i }) === [ 0, 1, 2 ]
LOVE2DEV.COM
Keep Arrays Dense
LOVE2DEV.COM
Enumerate Arrays Efficently
LOVE2DEV.COM
Don’t do useless work
setInterval(draw, 0);setTimeout(draw, 0);requestAnimationFrame(draw);setTimeout(draw, 1000 / 60);
Do avoid chattiness with the DOM
JavaScript
DOM
for (var i = 0; i < this.nOfBubbles; i++) { document.body.box.getElementById("ball0").style.left = b.x + "px"; document.body.box.getElementById("ball0").style.top = b.y + "px";}
Do check types of values from DOMthis.nOfBubbles =
document.getElementById(“dropDown").value;
30%of rendering time in string conversion
Slow Operations
11%Value
Conversions 18%
GC 17%
Your Code 45%
JavaScript: Flexibility or performance
Flexibility Performance
“Think C++”“Think Script”
Simple Websites Complex Apps, Games
var r = 3 * "10"; // r == 300
var a = new Array();a.push(10);
var p = {x: 0, y: 0};p.z = 5;p["some text"] = 1;p[1] = 2;eval("var s = p[1] * a[0]"); // s == 20
var r = 3 * parseInt("10");
var a = new Array(100);a[0] = 10;
var p = new Point(0, 0, 0);p.z = 5;
• C, C++, C# (Static Language)
• static int DoMath(int value) {• int result = 0;• for (int i = 0; i < 10000; i++) {
• for (int j = 0; j < 10000; j++) {
• result = i + j + value;
• }• }• return result;• }
JavaScript (Dynamic Language)function DoMath(value) { for (var i = 0; i < 10000; i++) { for (var j = 0; j < 10000; j++) { var result = i + j + value; } } return result;}
Stick to Integer MathWrite Fast JavaScript
Stick to Integer MathWrite Fast JavaScript
C++ JavaScriptDoMath(999);
40ms200ms (~5x)
DoMath(999/2);40ms
1600ms (~40x)
Stick to Integer MathWrite Fast JavaScript
0x005e22a0Pointer01 Type Tag449.4999999……… Value
02 Type Tag
“Hello World”Value
0x005e4148Pointer
Stick to Integer MathWrite Fast JavaScript
DoMath(Math.floor(999 / 2));
var b = Math.ceil((p[i].r + p[i].g + p[i].b) / 3);
Stick to Integer MathWrite Fast JavaScript
DoMath(Math.floor(999 / 2));
var b = Math.ceil((p[i].r + p[i].g + p[i].b) / 3);
Stick to Integer MathWrite Fast JavaScript
DoMath(Math.floor(999 / 2));
var b = Math.ceil((p[i].r + p[i].g + p[i].b) / 3);
Do write fast objects Add all properties in constructor Don’t delete properties Use identifiers for property names Use getters and setters sparingly Avoid conditionally adding properties Avoid default property values on prototype objects
Navigation & Performance Timing APIs Give You Access to Real Times Various Stages of Document Lifecycle
https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API http://www.html5rocks.com/en/tutorials/webperformance/basics/
Navigation & Performance Timing APIs
How to Build JavaScript Maintain Development, QA, Production Versions Use a Build Tool
Grunt, Gulp, WebPac, Broccoli, Node, etc
How to Build Production JavaScript Bundle & Minify
A Single Request is much faster to download and parse Compress
Gzip Content-Encoding Header
Set Proper Cache Headers CacheControl: "public, max-age=31449600, s-max-age=360“
Use A CDN Host on Static Server
How to Build Production JavaScript Node Modules Exists to Automate All these Requirements
Set it and Forget It!