User-Centric Web App Performance

Performance in Context of the User

The RAIL Model

per·for·mance

/pərˈfôrməns/

noun

  1. The time it takes for actions to complete before the user's eyes

suc·cess

səkˈses/

noun

  1. 😁

Performance ROI

*Diagram courtesy of Google (Paul Lewis & Paul Irish), "Introduction to RAIL (Chrome Dev Summit 2015)"

⌛️⌛️⏳

😭

😁

The User's Perception

*Diagram courtesy of Google (Paul Lewis & Paul Irish), "Introduction to RAIL (Chrome Dev Summit 2015)"

RAIL Method: 

An implementation-agnostic, high level, user-centric performance model

What is too slow?

What does the user feel?

User-centric Performance Goals

*Diagram courtesy of Google (Paul Lewis & Paul Irish), "Introduction to RAIL (Chrome Dev Summit 2015)"

esponse

R

A

I

L

Response

Applicable to inputs:

  • buttons
  • toggling form controls
  • starting animations

Goal: Visual response to click/tap in < 100ms

Where the connection between action and reaction breaks.

Response

🛠 Implementation Strategies:

  • Decouple the work from the visual response
  • Provide feedback for actions > 500ms
  • Instant visual response
  • Feedback on status of the action

Response

🛠 Implementation Strategies:

  • Optimistic UI's
    • Assume Success
    • Only delayed notifications are on server error
    • Respond with errors within 2 seconds, while still in user's flow

Examples:

nimation

R

A

I

L

Animation

  • Reasons why:
    • A smooth experience
    • Users notice frame rate variations
    • The standard for most devices today

Goal: Each frame completes in less than 16ms (60 fps)

Animation

  • The browser takes 6ms per frame to paint
  • You get 10ms per frame

*Diagram courtesy of Google (Paul Lewis), "Rendering Performance" - developers.google.com

The Pixel Pipeline

Animation

🛠 Implementation Strategies:

**For animations experiencing sub-optimal performance:

 

 

  • Avoid Animations that change the layout of the page
  • Animate using transform and opacity
  • Use will-change property - keeps browser from having to consider layout render or painting
.moving-element {
  will-change: transform;
}
.moving-element {
  transform: translateZ(0);
}

⚠️ Don't overuse

Animation

GO

🛠 Implementation Strategies:

  • Profiling animation performance
  • Example of will-change and transform

GO

dle

R

A

I

L

Idle Time

  • Minimize data loading in pre-rendering stage
  • Use idle time to load what you can
  • Yield control back to main thread every 50ms, so the 100ms response goal can be met

Goal: Use idle time to do work, while still satisfying the Response goal

// Creating a new Web Worker
const myWorker = new Worker("./worker.js");

// Giving work to the worker thread
myWorker.postMessage(arbitraryObject);
console.log("Message posted to worker");

main.js

  • Allows web content to run scripts in background threads
  • Each script is a worker
  • Can be used for processing, fetching, and storage interactions 

Idle Time

Implementation Strategies (freeing up the main thread):

Web Workers

🛠

Idle Time

Web Workers

...

// Handling result event from worker thread
myWorker.onmessage = function(e) {
  console.log(`
    Message received from worker:
    ${JSON.stringify(e.data)}
  `);
}

main.js

onmessage = function(e) {
  console.log(`
    Received object from the main script:
    ${JSON.stringify(e.data)}
  `);
  const workerResult = doWork(e.data);
  // Posting a message back to main.js
  postMessage(workerResult);
}

worker.js

Idle Time

Other Implementation Strategies (freeing up the main thread):

  • Request Animation Frame (RAF)
  • Async script tags

🛠

oad

R

A

I

L

Load

  • User attention wanders after 1 second

Goal: First meaningful paint in < 1000ms

Load

🛠 Implementation Strategies

  • Lazy loading - React Example:
class View extends React.Component {

    ...

    // This method is invoked immediately after
    // a component is mounted to the DOM.
    componentDidMount() {
        fetch("my-endpoint")
            .then(data => data.json())
            .then(json => this.setState({ pageData: json }))
            .catch(e => this.setState({ pageError: e }));
    }
    
    render() {
        return (
            <MostMeaningfulContent />
            {this.state.pageData && <SupplementalContent />}
        )
    }
}

Load

🛠 Implementation Strategies

  • Server-side rendering and caching
    • In-house options
    • Community options
  • Conditional loading:
    • Load on scroll
    • Load on event

🎊 The End 🎉

Sources

  • RAIL Model

    • https://developers.google.com/web/fundamentals/performance/rail

    • https://www.smashingmagazine.com/2015/10/rail-user-centric-model-performance/

  • Web App Performance High Level Strategies

    • https://developers.google.com/web/fundamentals/performance/rendering/

    • https://www.smashingmagazine.com/2016/11/true-lies-of-optimistic-user-interfaces/

  • Web App Performance Techniques

    • https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers

  • Optimizing Web App Animations

    • https://developers.google.com/web/fundamentals/design-and-ux/animations/

    • https://developers.google.com/web/fundamentals/design-and-ux/animations/animations-and-performance

    • https://medium.com/outsystems-experts/how-to-achieve-60-fps-animations-with-css3-db7b98610108

    • https://developers.google.com/web/fundamentals/performance/rendering/stick-to-compositor-only-properties-and-manage-layer-count

Web App Performance

By Evan Peterson

Web App Performance

Learn about improving the performance of your web app in ways that matter to the user i.e. in ways that will improve user happiness. The Google RAIL method is explained, and implementation strategies are presented as well.

  • 262
Loading comments...

More from Evan Peterson