Visualising Front-End Performance Bottlenecks

@richiemccoll

Frontend Engineer 

London 🇬🇧

@richiemccoll

Live and on demand sports streaming service.

@richiemccoll

Living Room devices

@richiemccoll

  • Samsung
  • Toshiba
  • Panasonic
  • (and more)

Smart Tvs

  • PS4
  • PS5
  • Xbox
  • (and more)

Games Consoles

  • Comcast
  • FireTV
  • SkyQ
  • (and more)

Set-top Boxes

@richiemccoll

What performance problems do we face?

  • Low memory/CPU targets
  • Resource competition on the main thread
  • Maintaining smooth 60fps interactions when navigating content

"Conversions go down 7% due to just one additional second of load time."

"39% of users stop engaging with a website if images take too long to load."

Source: Cloudflare - Getting Faster Performance whitepaper

@richiemccoll

To me, speedy software is the difference between an application smoothly integrating into your life, and one called upon with great reluctance."

@richiemccoll

What we will cover:

  • Measure, Analyse and Fix cycle
  • User Timings API
  • Live demo measuring and analysing
  • Virtualisation
  • Performance problems at DAZN
  • Fixing the performance bottleneck in the demo

@richiemccoll

The Measure, Analyse and Fix cycle 

@richiemccoll

Demo

git clone https://github.com/richiemccoll/visualising-front-end-performance-demo.git
git checkout before-fixes
npm i
npm start

@richiemccoll

https://aerotwist.com/blog/the-anatomy-of-a-frame/

@richiemccoll

Warning

Remember to measure against Production builds 

@richiemccoll

Measuring

How do we measure?

@richiemccoll

User Timings API

window.performance.mark



function createMark() {
  window.performance.mark('createMark-🎉-start');
  // ...
  window.performance.mark('createMark-🎉-end');
}

@richiemccoll

window.performance.measure



function createMarkAndMeasure() {
  window.performance.mark('createMark-🎉-start');
  // ...
  window.performance.mark('createMark-🎉-end');
  window.performance.measure(
   'createMark-🎂-measure',
   'createMark-🎉-start',
   'createMark-🎉-end'
  );
}

@richiemccoll

User Timings API

Creating a Baseline

  • Mark the start

  • usePrevious hook

  • Mark the end

  • Create the measure

@richiemccoll

Mark the start

<button
  onClick={() => {
   window.performance.mark("changingOrder-start");
   setOrder();
  }}
  className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2   px-4 rounded"
>
 Click to view {order} launches
</button>

Measuring and Analysing 

@richiemccoll

Store the value from the previous render in a ref.

Measuring and Analysing 

usePrevious





function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
   ref.current = value;
  });
  return ref.current;
}

@richiemccoll

Measuring and Analysing 

Mark the End

function LatestLaunchList({ launches, setOrder, order = "older" }) {
  const prevOrder = usePrevious(order);
  useEffect(() => {
    if (prevOrder && prevOrder !== order) {
      performance.mark("changingOrder-end");
      performance.measure(
      "changingOrder-measure",
      "changingOrder-start",
      "changingOrder-end"
    );
   }
 }, [order, prevOrder]);
 
 // ... 
}

@richiemccoll

Analyse 

What is the baseline?

@richiemccoll

Virtualisation

List Virtualisation” or “windowing”.

image: https://web.dev/virtualize-long-lists-react-window/

@richiemccoll

TV Virtualisation

DAZN

@richiemccoll

TV Virtualisation

DAZN

@richiemccoll

Constraints on TV

  • Focus Management
  • Wide range of Hardware specifications
    • Low memory/Low CPU
  • Wide range of Browser engines 
  • Support (or lack of) modern web standards
  • Lack of developer tools

@richiemccoll

"Write once, run everywhere"

(and more)

@richiemccoll

Before

After

Scripting: 6849ms

Scripting: 4554ms

Style: 1475ms

Style: 836ms

Paint: 506ms

Paint: 205ms

@richiemccoll

(-34%)

(-43%)

(-59%)

Chrome Remote Debug Profile on FireTV with playback

January 2020

Virtualised Cards

https://github.com/jaredLunde/masonic

import { Masonry } from 'masonic';

<div className="flex flex-wrap -m-4">
 <Masonry
   items={launches}
   columnWidth={300}
   render={({ data: launch }) => {
   return (
    <Card
     name={launch.name}
     details={launch.details}
     image={launch.imgUrl}
     url={launch.url}
     date={launch.date}
    />
  );
}}
/>
</div>

"A performant and versatile virtualized masonry grid for React"

@richiemccoll

Measure and Analyse 

What is the new baseline?

@richiemccoll

Remember

Measure against a Production build

Conclusion 

  • Measure, Analyse and Fix

  • User Timings API

  • Virtualisation

@richiemccoll

Thank you!

@richiemccoll

How to React to Performance Bottlenecks

By Richie McColl

How to React to Performance Bottlenecks

Measuring, analysing and fixing slow running Javascript code.

  • 403