Browser Rendering Optimization

Building 60 FPS Web Apps

Oleksii Kachura

Things to talk about

  • Critical Rendering Path
  • App Lifecycles
  • Tools
  • Optimizations
    • JavaScript
    • Styles
    • Layout
    • Painting and Compositing

Why?

  1. We want our apps to be smooth.
  2. Users want our apps to be smooth.

Critical Rendering Path

From raw bytes to pixels on your screen (in 1s)

CRP

CRP

HTTP/2

Example

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>

    <p>Hello <span>web performance </span>students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>
/* style.css */

body   { font-size: 16px; }
p      { font-weight: bold; }
span   { color: red; }
p span { display: none; }
img    { float: right; }

HTML

Conversion

Tokenizing

Lexing

DOM construction

CSS

/* style.css */

body   { font-size: 16px; }
p      { font-weight: bold; }
span   { color: red; }
p span { display: none; }
img    { float: right; }

Render tree

Remember

  • HTML is parsed incrementally
  • CSS is parsed non-incrementally
  • CSS is render blocking
  • JavaScript is parser blocking
    • Possible solution - async/defer
...
<script src="example.js" async></script>
<script src="example.js" defer></script>
...

Minimize

  • Number of critical resources.
  • Number of critical bytes.
  • Critical path length.

Layout

Hello students

<p> (100%)

<img>

<div> (100%)

<html> <body> (viewport width=device-width)

Paint

Paint

Hello students

<p> (100%)

<img>

<div> (100%)

<html> <body> (viewport width=device-width)

Rasterizer draw calls:

  1. save
  2. clipRect
  3. save
  4. clipRect
  5. drawRect
  6. drawTextBlob
  7. drawTextBlob
  8. restore
  9. restore
  10. save
  11. clipRect
  12. save
  13. clipRect
  14. drawRect
  15. drawBitmapRectToRect
  16. restore

+        imageDecode + [Resize]

Composite Layers

Composite Layers

Composite Layers

App Lifecycles

RAIL / LIAR

App phases

Response
Animate
Idle
Load

1000

50

16

100

= 1 s / 60 frames
=1s/60frames= 1 s / 60 frames

ms

Typical Frame

CSS Animations

Web Animation API

Style

Layout

Paint

Composite

JavaScript

Tools and Examples

First measure then optimize

DEMO

Optimizations

JS, Styles and Layout, Paint and Composite

JavaScript

  • Just In Time (JIT) Compiler
  • requestAnimationFrame
  • Web Workers + demo

JIT example



Function.prototype.toString()

V8

Micro-optimization

// Which is faster:

for (var i = 0; i < len; i++) ...

// or

while (++i < len) ...

// ?
// We don't know

requestAnimationFrame

function animate() {
    // cool animation frame stuff
    requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

Style

Layout

Paint

Composite

JavaScript

#1

function animate() {
    // cool animation frame stuff
    setTimeout(animate, 4);
}

animate();

requestAnimationFrame

Web Workers

HTML5

Worker

worker.js

main-script.js

postMessage(data)

postMessage(data)

onmessage

onmessage

var worker = new Worker('worker.js');

worker.onmessage = function(e) {
    console.log('Worker said: ', e.data);
};

worker.postMessage('Hello World');
this.onmessage = function(e) {
    // long-running JS goes here
    postMessage(e.data);
};

Web Workers

DEMO

Limitations of Web Workers

  • Start-up performance cost
  • Memory cost for worker instance
  • No access to DOM, window, navigator etc.
  • Everything passed to a worker is copied entirely (exception - Transferrable Objects can be zero-copied)

JavaScript

  • Avoid micro-optimizations.
  • For visual updates use requestAnimaitonFrame rather than setTimeout/setInterval.
  • Move long-running JavaScript to Web Workers.

Styles

  • Reduce the complexity of your selectors.
  • Use a class-centric methodology like BEM.
  • Reduce the number of elements on which style calculation must be calculated.

Styles

<section class="post">
  <h1 class="title">Egestas</h1>
  <p class="description big">Pellentesque morbi turpis egestas.</p>    
</section>
<section class="post">
  <h1 class="post__title">Egestas</h1>
  <p class="post__description--big">Pellentesque morbi turpis egestas.</p>
</section>

.post {}
.post .title {}
.post .description .big {}

.post {}
.post__title {}
.post__description--big {}
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
.item:nth-child(3) {
 color: #0f0;
}
<div class="item"></div>
<div class="item"></div>
<div class="item third"></div>
.item.third {
 color: #0f0;
}
<div class="item"></div>
<div class="item"></div>
<div class="item--third"></div>
.item--third {
 color: #0f0;
}

Layout

  • Use new flexboxes.
  • Avoid triggering layout wherever possible.
  • Avoid Forced Synchronous Layouts (FSL):
    • for loops that force layout & change the DOM are the worst, avoid them.
    • Batch your writes & reads to the DOM (via fastDOM or virtual DOM implementation).
requestAnimationFrame(logBoxHeight);

function logBoxHeight() {

  box.classList.add('super-big');

  console.log(box.offsetHeight);
}
requestAnimationFrame(logBoxHeight);

function logBoxHeight() {

  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

Paint and Compositing

  • Avoid paint where you can.
  • Changing any property apart from transforms or opacity always triggers paint.
  • Promote layers - reduce paint areas.
    • Layout boundaries
    • will-change and transform: translateZ(0)
    • Promote elements that move or fade.
  • Avoid overusing promotion; layers require memory and management.

DEMO

Thanks!

May the Forced syncronous layout NOT be with you!

Useful Links

Browser Rendering Optimization

By alex-kachura

Browser Rendering Optimization

Building 60 fps web apps

  • 6,595