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

Made with Slides.com