Upgrade to Pro — share decks privately, control downloads, hide ads and more …

🇬🇧 CityJS London 2026 (Workshop)

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

🇬🇧 CityJS London 2026 (Workshop)

React: Internals and Advanced Performance Patterns

Keeping user interfaces smooth becomes harder as React applications scale, especially across different devices, networks, and workloads. Understanding how React actually schedules and renders work can turn performance tuning from guesswork into engineering.

In this session, we’ll dive into React Fiber and reconciliation, connecting them to classic computer science concepts like cooperative scheduling and incremental work.

From there, we’ll explore practical strategies for production React apps, along with a few browser-level primitives that influence how quickly users actually see content. Finally, we’ll look at how to measure responsiveness in the real world using modern web performance tooling.

The goal is to build the mental models that let you reason about performance problems in React and the web platform.

Avatar for Matheus Albuquerque

Matheus Albuquerque PRO

April 16, 2026

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. Matheus Albuquerque ↝ 👨💻 STAFF SWE @ MEDALLIA ↝ ⚛

    CHAIR @ REACT SUMMIT NYC ↝ ⚡ GOOGLE DEVELOPER EXPERT ↝ 𝕏 YTHECOMBINATOR
  2. Which browsers are visiting our app? REACT: INTERNALS AND ADVANCED

    PERFORMANCE PATTERNS — APP DYNAMICS REPORT • 2022
  3. Brainwave analysis from the experiment revealed that participants had to

    concentrate up to 50% more when using websites via the slower connection. — Study conducted by Foviance on behalf of CA • 2011 FRUSTRATION → STRESS
  4. Delayed web pages caused a 38% rise in mobile users'

    heart rates — equivalent to the anxiety of watching a horror movie alone. — Ericsson ConsumerLab • 2015 FRUSTRATION → ANXIETY
  5. “[…] With React you can build applications without even thinking

    about performance and the default state is fast.” — Rethinking Best Practices • Pete Hunt, 2013
  6. ↝ HOW QUICKLY A PAGE CAN LOAD AND RENDER ALL

    OF ITS VISUAL ELEMENTS TO THE SCREEN? ↝ HOW QUICKLY A PAGE CAN LOAD AND RUN ANY REQUIRED JAVASCRIPT IN ORDER FOR COMPONENTS TO RESPOND TO USER INTERACTION? ↝ DO TRANSITIONS AND ANIMATIONS RENDER AT A CONSISTENT FRAME RATE AND FLOW FLUIDLY? WHAT DOES IT MEAN TO BE FAST?
  7. PERF MITIGATORS: ↝ shouldComponentUpdate, React.PureComponent ↝ React.memo ↝ useMemo, useCallback

    ↝ useTransition, useDeferredValue, React.Suspense & others! MAKING THINGS “FAST”
  8. […] “While browsing HackerNews, I sometimes get the feeling that

    every developer out there is working for FAANG, as there are always posts from those people doing some hyped stu f . Or you might think that PHP is never used nowadays because whenever it’s mentioned, everyone is hating on it in the comments.” […] — The silent majority • Vadim Kravcenko, 2022
  9. […] “But let’s be straight, that’s like 1% of all

    of the developers out there — the rest of them are just lurking and coding with their language of choice and being content with it. Be it Fortran, COBOL, Perl, or PHP.” […] — The silent majority • Vadim Kravcenko, 2022
  10. ↝ ISG • SSR • STREAMING SSR ↝ PROGRESSIVE •

    SELECTIVE • PARTIAL HYDRATION ↝ ISLANDS ARCHITECTURE • RESUMABILITY ↝ POPULAR REACT HOOKS • (META) FRAMEWORKS ↝ COMPILERS AND STATIC ANALYSIS 🙁 ↝ FINE-GRAINED REACTIVITY AND SIGNALS WE’LL NOT FOCUS ON…
  11. APPLICATION HOLOTYPES Portfolio Content Storefront Social Network I m m

    ersive Holotype Personal Blog CNN Amazon Facebook Figma Interactivity Minimal Linked Articles Purchase Multi-Point, Real-time Everything Session Depth Shallow Shallow Shallow - Medium Extended Deep Values Simplicity Discover-ability Load Performance Dynamicism I m m ersiveness Routing Server Server, HTML Swap HTML Swap, Hybrid Hybrid, Client Client Rendering Static Static, SSR Static, SSR SSR CSR Hydration None Progressive, Partial Partial, Resumable Any None (CSR) Frameworks 11ty Astro, Elder Marko, Qwik, Hydrogen Next, Remix Create React App — PATTERNS FOR BUILDING JAVASCRIPT WEBSITES IN 2022 • RYAN CARNIATO
  12. ↝ REVISITING COMPUTER SCIENCE CONCEPTS. ↝ UNDERSTANDING HOW TOOLS WORK

    UNDER THE HOOD AND THE RATIONALES BEHIND THEM BY CHECKING THEIR SOURCE CODE. ↝ LEVERAGING REAL-WORLD CASE STUDIES FROM SMALL, MEDIUM, AND ENTERPRISE-SCALE COMPANIES. ↝ MICRO EXPERIMENTS AND THEIR RESULTS. METHODOLOGY
  13. This workshop is designed to empower you with the knowledge

    and tools needed to tackle a variety of complex React and front-end performance challenges in your personal and professional projects. Also, it’s meant to bridge the gap between foundational computer science concepts and practical front-end development. — React: Internals and Advanced Performance Patterns • Matheus, 2026
  14. ↝ SCHEDULING WORK ↝ PREDICTING WORK & PRIORITIZING WORK ↝

    CONTINUITY WORK ↝ OTHER TECHNIQUES ↝ MEASURING ↝ THE FUTURE & CLOSING NOTES METHODOLOGY: TOPICS
  15. ↝ CLONING THE REPO NOW. ↝ GETTING THE SLIDES LATER.

    ↝ QUESTIONS AT THE END OF EACH SECTION. ↝ 10 MINUTES BREAK. METHODOLOGY: STEPS
  16. THIS SECTION PRESENTS… #1 FIBER(S) OVERVIEW • UNITS OF WORK

    • IN NODE • OUT THERE #3 EFFECT HANDLERS OVERVIEW • IN REACT • OUT THERE #2 COROUTINES OVERVIEW • OUT THERE #4 SCHEDULING TASKS • LONG TASKS • TASK RUNNING STRATEGIES
  17. THIS SECTION PRESENTS… #6 SCHEDULING ON THE WEB OVERVIEW •

    NATIVE SCHEDULING API #5 SCHEDULING IN REACT OVERVIEW • HEURISTICS • PRIORITY LEVELS • RENDER LANES • USE CASES
  18. STACK FRAMES let frame: Frame = { return: frame, fn:

    add, parameters: [2, 2], localVariables: { result: 4, }, } function add(x,y) { const result = x + y; return result; } add(2, 2)
  19. STACK FRAMES let frame: Frame = { return: frame, fn:

    add, parameters: [2, 2], localVariables: { result: 4, }, } let fiber: Fiber = { return: fiber, component: Avatar, props: { id: 4 }, state: { isLoaded: true, }, }
  20. FIBERS ↝ FIBER ARCHITECTURE: REACT-SPECIFIC IMPLEMENTATION OF A CALL-STACK-LIKE MODEL

    WHERE REACT HAS FULL CONTROL OF SCHEDULING WHAT SHOULD BE DONE. ↝ FIBER: A STACK FRAME FOR A REACT COMPONENT.
  21. UNITS OF WORK ONCE A TEMPLATE GOES THROUGH THE JSX

    COMPILER, YOU END UP WITH A BUNCH OF REACT ELEMENTS. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES.
  22. UNITS OF WORK DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT

    RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END UP WITH A BUNCH OF REACT ELEMENTS. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
  23. UNITS OF WORK DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT

    RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END UP WITH A BUNCH OF REACT ELEMENTS. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  24. UNITS OF WORK DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT

    RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END UP WITH A BUNCH OF REACT ELEMENTS. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
  25. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE

    RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END UP WITH A BUNCH OF REACT ELEMENTS. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. AND THAT MAKES IT A CONVENIENT WAY TO TRACK, SCHEDULE, PAUSE AND ABORT THE WORK. UNITS OF WORK
  26. “Homoiconicity is a property of some programming languages in which

    the code used to express a program is written using the data structures of that language.” — Wikipedia
  27. HOMOICONICITY (let [x 1] (inc x)) ; = > 2

    PERFORMS A TEMPORARY BINDING (BINDS X TO THE VALUE 1)
  28. HOMOICONICITY (let [x 1] (inc x)) ; = > 2

    INCREMENTS X TO GIVE THE RETURN VALUE OF 2
  29. HOMOICONICITY IT CAN BE THOUGHT OF AS A LIST WITH

    THREE ELEMENTS: ↝ A SYMBOL NAMED LET ↝ A VECTOR WITH TWO ELEMENTS ↝ A LIST WITH TWO ELEMENTS
  30. HOMOICONICITY IT CAN BE THOUGHT OF AS A LIST WITH

    THREE ELEMENTS: ↝ A SYMBOL NAMED LET ↝ A VECTOR WITH TWO ELEMENTS ↝ A LIST WITH TWO ELEMENTS A SYMBOL (X) AND AN INTEGER A SYMBOL (INC) AND A SYMBOL (X)
  31. ↝ REACT ELEMENTS ARE JUST DATA. ↝ JUST LIKE IN

    LISP, REACT COMPONENTS CAN MANIPULATE THEIR CHILDREN AND RETURN COMPLETELY DIFFERENT THINGS. HOMOICONICITY + REACT
  32. “[…] Pattern matching consists of specifying patterns to which some

    data should conform and then checking to see if it does and deconstructing the data according to those patterns.” — Learn You a Haskell
  33. PATTERN MATCHING factorial : : (Integral a) = > a

    - > a factorial 0 = 1 factorial n = n * factorial (n - 1)
  34. PATTERN MATCHING fib : : (Integral a) = > a

    - > a fib 0 = 1 fib 1 = 1 fib n | n > = 2 = fib (n-1) + fib (n-2) factorial > factorial 0 = factorial n =
  35. PATTERN MATCHING / / . . . export function isWhen<Shape

    extends {}>( child: ElementWithMetadataUnion<Shape> ): child is ElementWithMetadata<WhenProps<Shape > > { return child.element.type === When; } / / . . . export function nodesToElementWithMetadata<Shape extends {}>( children: ReactNode ) { return Children.toArray(children).map((element, idx) = > ({ element: element, position: idx, })) as Array<ElementWithMetadata<Shape > > ; } / / . . .
  36. PATTERN MATCHING / / . . . export function isWhen<Shape

    extends {}>( child: ElementWithMetadataUnion<Shape> ): child is ElementWithMetadata<WhenProps<Shape > > { return child.element.type === When; } / / . . . export function nodesToElementWithMetadata<Shape extends {}>( children: ReactNode ) { return Children.toArray(children).map((element, idx) = > ({ element: element, position: idx, })) as Array<ElementWithMetadata<Shape > > ; } / / . . .
  37. PATTERN MATCHING const supportsSensor = () = > Boolean(window.AmbientLightSensor); const

    AmbientLight = React.lazy(() = > import("./AmbientLight")); const Fallback = React.lazy(() = > import("./Fallback")); export default function MyComponent() { const { Match, When, Otherwise } = usePatternMatch(); return ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); }
  38. PATTERN MATCHING const supportsSensor = () = > Boolean(window.AmbientLightSensor); const

    AmbientLight = React.lazy(() = > import("./AmbientLight")); const Fallback = React.lazy(() = > import("./Fallback")); export default function MyComponent() { const { Match, When, Otherwise } = usePatternMatch(); return ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING + REACT.SUSPENSE + REACT.LAZY() = USERS DOWNLOAD ONLY THE COMPONENT BUNDLE THAT MATCHES.
  39. PATTERN MATCHING const supportsSensor = () = > Boolean(window.AmbientLightSensor); const

    AmbientLight = React.lazy(() = > import("./AmbientLight")); const Fallback = React.lazy(() = > import("./Fallback")); export default function MyComponent() { const { Match, When, Otherwise } = usePatternMatch(); return ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING + REACT.SUSPENSE + REACT.LAZY() = USERS DOWNLOAD ONLY THE COMPONENT BUNDLE THAT MATCHES. MANIPULATING BASED ON ELEMENTS DATA.
  40. USING FIBERS, REACT CAN: ↝ PAUSE, RESUME, AND RESTART RENDERING

    WORK ON COMPONENTS AS NEW UPDATES COME IN. ↝ REUSE PREVIOUSLY COMPLETED WORK. ↝ SPLIT WORK INTO CHUNKS AND PRIORITIZE TASKS BASED ON IMPORTANCE. FIBERS IN REACT: RECAP
  41. ↝ ASYNCHRONICITY IN JAVASCRIPT IS CONTAGIOUS. ↝ IF ANY FUNCTION

    IS ASYNC, THEN EVERYTHING THAT CALLS IT MUST ALSO BE ASYNC… ↝ …AND SO ON UNTIL THE ENTIRE PROGRAM IS ASYNCHRONOUS. ASYNCHRONICITY IN JAVASCRIPT
  42. ↝ ASYNCHRONICITY IN JAVASCRIPT ISN’T FREE. ↝ EVERY ASYNC FUNCTION

    CALL HAS TO: ↝ ALLOCATE CALLBACKS & STORE THEM SOMEWHERE. ↝ TAKE A TRIP BACK TO THE EVENT LOOP BEFORE INVOKING THOSE CALLBACKS. ASYNCHRONICITY IN JAVASCRIPT
  43. ↝ ITS API HAS TWO MAIN FUNCTIONS FOR COMPILING SASS

    FILES: ONE SYNC AND ONE ASYNC. ↝ THE ASYNC ONE BECAME WIDELY USED IN PRACTICE BECAUSE IT ENABLED ASYNC PLUGINS (E.G. WEBPACK’S SASS-LOADER). ASYNCHRONICITY & SASS
  44. ↝ FOR NODE SASS, THE PERFORMANCE DIFFERENCE WAS NEGLIGIBLE, BECAUSE

    IT WAS BUILT ON C++. ↝ HOWEVER, DART SASS RUNS AS PURE JAVASCRIPT, WHICH MAKES IT SUBJECT TO JAVASCRIPT’S ASYNCHRONICITY RULES. ASYNCHRONICITY & SASS
  45. ↝ THE ASYNC VERSION IN DART SASS WAS 2-3X SLOWER

    THAN THE SYNC ONE. ↝ THEY STARTED USING NODE-FIBERS TO IMPLEMENT THE ASYNC API USING THE FAST, SYNC, CODE. ASYNCHRONICITY & SASS
  46. ↝ A FIBER IS A LIGHTWEIGHT, COOPERATIVE, CONCURRENT EXECUTION UNIT.

    ↝ FIBERS ARE A COMMON RESOURCE IN SOME OPERATING SYSTEMS AND IN SOME PROGRAMMING LANGUAGES. ↝ RUNTIMES USUALLY INCLUDE A SCHEDULER THAT SCHEDULES THE EXECUTION OF FIBERS. FIBERS OUT THERE
  47. “This attitude does not only work in the context of

    the game industry, though. Any other industry with strong architectural requirements can be a source of inspiration and knowledge for us and help us write better code on the web” An Actor, a model and an architect walk onto the web... • Surma
  48. COROUTINES IN REACT THE IDEA BEHIND COROUTINES — AS OPPOSED TO FIBERS — WAS

    TO GIVE COMPONENTS EXPLICIT CONTROL OVER YIELDING AND RESUMPTION. COROUTINES APPEARED WHEN WORK ON FIBER WAS FIRST GOING AS A SPECIFIC COMPONENT TYPE.
  49. COROUTINES VS. FIBERS FIBERS CONTROL IS PASSED TO A SCHEDULER

    WHICH DETERMINES WHAT TO RUN NEXT. COROUTINES CONTROL IS PASSED TO THE CALLER AND HANDLED BY APPLICATION CODE.
  50. COROUTINES VS. FIBERS ↝ BOTH DECIDE WHEN TO DROP CONTROL

    (AKA. YIELD). ↝ COROUTINES CAN BE USED TO IMPLEMENT FIBERS BY ALWAYS YIELDING TO A SCHEDULER COROUTINE. ↝ FIBERS CAN BE USED TO IMPLEMENT COROUTINES BY ALLOWING EACH FIBER TO COMMUNICATE TO THE SCHEDULER WHICH FIBER SHOULD BE RUN WHEN IT YIELDS.
  51. EFFECT HANDLERS APPROACH TO REASONING ABOUT COMPUTATIONAL EFFECTS IN PURE

    CONTEXTS. ↝ EFFECT: A SET OF OPERATIONS. ↝ EFFECT HANDLER: RESPONSIBLE FOR HANDLING THE SEMANTICS OF HOW TO IMPLEMENT EFFECTS.
  52. EFFECT HANDLERS: EFF (* state.eff *) type user = string

    * int effect Get: user effect Set: user - > unit
  53. EFFECT HANDLERS: EFF (* state.eff *) type user = string

    * int effect Get: user effect Set: user - > unit A USER WITH A NAME AND AGE.
  54. EFFECT HANDLERS: EFF (* state.eff *) type user = string

    * int effect Get: user effect Set: user - > unit WE DEFINE EFFECTS WITH THE effect KEYWORD AND A TYPE SIGNATURE.
  55. EFFECT HANDLERS: EFF let state = handler | y -

    > fun currentState - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;;
  56. EFFECT HANDLERS: EFF let state = handler | y -

    > fun currentState - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; WE HAVE A handler WITH THREE BRANCHES, AND ALL OF THEM RETURN A FUNCTION.
  57. EFFECT HANDLERS: EFF let state = handler | y -

    > fun currentState - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; NO EFFECT (WHEN WE REACH THE END OF THE BLOCK). y IS THE RETURN VALUE.
  58. EFFECT HANDLERS: EFF let state = handler | y -

    > fun currentState - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; MATCHING OUR EFFECTS.
  59. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; EFFECT HANDLERS: EFF k IS A CONTINUATION. IT REPRESENTS THE REST OF THE COMPUTATION AFTER WHERE WE PERFORM AN EFFECT.
  60. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } }
  61. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } }
  62. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } } THROW → PERFORM CATCH → HANDLE LETS US JUMP BACK TO WHERE WE PERFORMED THE EFFECT.
  63. EFFECT HANDLERS ↝ IT DOESN'T REALLY MATTER HOW WE HOLD

    STATE. ↝ WITH PROMISES, IF WE WERE TO CHANGE IN THE FUTURE, THAT’D REQUIRE CHANGES ACROSS EVERYTHING. ↝ WITH ALGEBRAIC EFFECTS, WE CAN SIMPLY STOP THE CURRENT PROCESS ALTOGETHER UNTIL OUR EFFECTS ARE FINISHED.
  64. LAYOUT ALGORITHM THE REACT TEAM APPARENTLY SPENT SOME TIME EXPERIMENTING

    WITH EFFECT-HANDLER CONTROL STRUCTURES FOR MANAGING LAYOUT.
  65. #3 Side e ff ects within a component REACT: INTERNALS

    AND ADVANCED PERFORMANCE PATTERNS
  66. function ThemeBorderColorRequest() { } function FancyBox(children) { const color =

    raise new ThemeBorderColorRequest(); return { borderWidth: '1px', borderColor: color, children: children }; } function BlueTheme(children) { return try { children(); } catch effect ThemeBorderColorRequest - > [, continuation] { continuation('blue'); } } function App(data) { return BlueTheme( FancyUserList.bind(null, data.users) ); }
  67. function ThemeBorderColorRequest() { } function FancyBox(children) { const color =

    raise new ThemeBorderColorRequest(); return { borderWidth: '1px', borderColor: color, children: children }; } function BlueTheme(children) { return try { children(); } catch effect ThemeBorderColorRequest - > [, continuation] { continuation('blue'); } } function App(data) { return BlueTheme( FancyUserList.bind(null, data.users) ); } THROW → RAISE CATCH → CATCH EFFECT
  68. HOOKS API ↝ ALGEBRAIC EFFECTS = A SET OF OPERATIONS

    AND A SET OF EFFECT HANDLERS. ↝ THE OPERATIONS HERE ARE OUR HOOKS (E.G. useState, useEffect, AND SO ON). ↝ WE HAVE TO SET UP HANDLERS IN EFF; IN REACT THEY'RE SET UP AS PART OF THE RENDER CYCLE.
  69. HOOKS API ↝ REACT IS RESPONSIBLE FOR MUCH OF THE

    IMPLEMENTATION OF WHEN/HOW OUR EFFECTS RUN. ↝ BY SPLITTING EFFECTS AND RENDERING, WE ALLOW IT TO RELIEVE US OF SOME COMPLEXITY.
  70. SUSPENSE INTERNALS A COMPONENT IS ABLE TO SUSPEND THE FIBER

    IT IS RUNNING IN BY THROWING A PROMISE, WHICH IS CAUGHT AND HANDLED BY THE FRAMEWORK.
  71. SUSPENSE INTERNALS A COMPONENT IS ABLE TO SUSPEND THE FIBER

    IT IS RUNNING IN BY THROWING A PROMISE, WHICH IS CAUGHT AND HANDLED BY THE FRAMEWORK. THROW → HANDLE → RESUME PATTERN.
  72. TASKS A UNIT OF WORK THAT THE BROWSER DOES TO

    RENDER A FRAME. JAVASCRIPT STYLES LAYOUT PAINT COMPOSITE
  73. LONG TASKS ↝ IF A TASK TAKES MORE THAN 50

    MS, USER INPUT FEELS DELAYED. ↝ BASED ON THE USER-CENTRIC PERFORMANCE MODEL CALLED RAIL. ↝ THEY TAKE TOO LONG AND BLOCK OTHER TASKS.
  74. #question 🤔 How to avoid blocking the main thread? REACT:

    INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  75. TASK RUNNING STRATEGIES ↝ PARALLELISM: MULTIPLE THREADS = MULTIPLE TASKS

    AT THE SAME TIME ON SEPARATE CPU CORES. ↝ CONCURRENCY: SINGLE THREAD + QUICKLY SWITCHING BETWEEN TASKS. ↝ SCHEDULING: CONCURRENCY + TASK PRIORITIZATION.
  76. WEB WORKERS ↝ DATA EXCHANGE IS THROUGH MESSAGE-PASSING. ↝ NO

    ACCESS TO ANY VARIABLES/CODE FROM THE PAGE THAT CREATED THEM OR VICE VERSA. ↝ NO ACCESS TO THE DOM, MAKING UI UPDATES FROM A WORKER BARELY IMPOSSIBLE. ↝ TWO MODELS: ACTORS & SHARED MEMORY.
  77. WEB WORKERS: ACTORS ↝ EACH ACTOR MAY OR MAY NOT

    RUN ON A SEPARATE THREAD AND FULLY OWNS THE DATA IT IS OPERATING ON. ↝ ACTORS CAN ONLY SEND/REACT TO MESSAGES. ↝ MAIN THREAD = ACTOR THAT OWNS THE DOM/UI.
  78. WEB WORKERS: ACTORS ↝ EVERY MESSAGE WE SEND NEEDS TO

    BE COPIED. ↝ BALANCE: MOVING CODE TO A WORKER VS COMMUNICATION OVERHEAD/WORKER BEING BUSY. ↝ postMessage IS A FIRE-AND-FORGET MESSAGING MECHANISM WITH NO BUILT-IN UNDERSTANDING OF REQUEST AND RESPONSE.
  79. WEB WORKERS: ACTORS ↝ ONE DEDICATED TYPE: SharedArrayBuffer. ↝ A

    LINEAR CHUNK OF MEMORY THAT CAN BE MANIPULATED USING TypedArrays OR DataViews. ↝ IF SENT VIA postMessage, THE OTHER END GETS A HANDLE TO THE EXACT SAME MEMORY CHUNK.
  80. WEB WORKERS: ACTORS ↝ MOST OF THE APIS ARE BUILT

    NO CONCURRENT ACCESS TO OBJECTS IN MIND. ↝ YOU BUILD YOUR OWN MUTEX ABSTRACTIONS AND OTHER CONCURRENT DATA STRUCTURES. ↝ NO DIRECT WAY OF WORKING ON FAMILIAR OBJECTS/ ARRAYS; JUST A SERIES OF BYTES.
  81. WORKERS: WEB ASSEMBLY ↝ WORKERS + SharedArrayBuffers TO SUPPORT THE

    THREADING MODEL OF C++ AND OTHERS. ↝ THE BEST EXPERIENCE FOR SHARED-MEMORY MODEL. ↝ FASTER THAN JS WHEN YOU STAY WITHIN WASM, BUT THE MORE YOU HAVE TO CROSS OVER TO JS APIS THE SLOWER IT IS.
  82. WORKERS: WEB ASSEMBLY ↝ JAVASCRIPT IS OFTEN FASTER AT DOING

    DOM RENDERING. ↝ HIGH-LEVEL LIBRARIES CAN BE MORE PERFORMANT THAN LOW-LEVEL WASM IMPLEMENTATIONS. ↝ DOESN’T OFFER LOT OF THE BENEFITS (AND COMFORT) OF JAVASCRIPT.
  83. WORKERS ↝ GOOD FOR DATA PROCESSING AND CRUNCHING NUMBERS. ↝

    HARD TO USE FOR UI-RELATED STUFF. ↝ HARDER THAN ADJUSTING IT FOR A SCHEDULER.
  84. Expensive component with a CPU-bound operation + our custom scheduler.

    REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  85. function* resourcefulOperation(value: number) { let newValue = String(value); while (true)

    { yield; for (let i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } } const initialValue = 0; const scheduler = new Scheduler(resourcefulOperation, initialValue); function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = scheduler.performUnitOfWork(value); return <p>{result}</p>; } PROMOTED TO A GENERATOR YIELDING EXECUTION DOING CONCURRENT TASKS
  86. function resourcefulOperation(value: number) { let newValue = String(value); for (let

    i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = resourcefulOperation(value); return <p>{result}</p>; } SCHEDULING WITH… OUR SCHEDULER
  87. function resourcefulOperation(value: number) { let newValue = String(value); for (let

    i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } function ResourcefulComponent(props: { value: number }) { const [_, startTransition] = useTransition(); const [result, setResult] = useState(""); useEffect(() = > { startTransition(() = > { const newResult = resourcefulOperation(props.value); setResult(newResult); }); }, [props.value]); return <p>{result}</p>; } SCHEDULING WITH… OUR SCHEDULER
  88. HEURISTICS ↝ A COOPERATIVE MULTITASKING MODEL. ↝ A SINGLE INTERRUPTIBLE

    RENDERING THREAD. ↝ RENDERING CAN BE INTERLEAVED WITH OTHER MAIN THREAD TASKS AND OTHER REACT RENDERS. ↝ AN UPDATE CAN HAPPEN IN THE BACKGROUND WITHOUT BLOCKING THE RESPONSE TO NEW INPUT.
  89. HEURISTICS ↓ ORIGINAL RENDER TASK USER INPUT → ↑ HIGHER

    PRIORITY RENDER TASK ↓ RESUME ORIGINAL RENDER TASK
  90. HEURISTICS ↝ IT YIELDS EXECUTION IS BACK TO THE MAIN

    THREAD EVERY 5MS. ↝ IT'S SMALLER THAN A SINGLE FRAME EVEN ON 120FPS, SO IT WON'T BLOCK ANIMATIONS. ↝ IN PRACTICE, RENDERING IS INTERRUPTIBLE.
  91. PRIORITY LEVELS PRIORITY TIMEOUT WHEN I m m ediate SYNCHRONOUSLY

    TASKS THAT NEED TO RUN SYNCHRONOUSLY UserBlocking 250MS RESULTS OF A USER INTERACTION (E.G. A BUTTON CLICK) Normal 5S UPDATES THAT DON’T HAVE TO FEEL INSTANTANEOUS Low 10S TASKS THAT CAN BE DEFERRED BUT MUST STILL COMPLETE EVENTUALLY (E.G. AN ANALYTICS NOTIFICATION) Idle NO TIMEOUT TASKS THAT DO NOT HAVE TO RUN AT ALL (E.G. HIDDEN OFFSCREEN CONTENT)
  92. RENDER LANES ↝ ONE LANE: ONE BIT IN A BITMASK.

    ↝ ONE UPDATE IN REACT: ONE LANE. ↝ ONE RENDER IN REACT: ONE OR MORE LANES. ↝ UPDATES IN THE SAME LANE: RENDER IN THE SAME BATCH. ↝ DIFFERENT LANES: SEPARATE BATCHES.
  93. RENDER LANES ↝ 31 LEVELS OF GRANULARITY (= ONE BITMASK).

    ↝ ALLOWS TO CHOOSE WHETHER TO RENDER MULTIPLE TRANSITIONS IN A SINGLE BATCH OR RENDER THEM INDEPENDENTLY. ↝ REDUCES OVERHEAD OF MULTIPLE LAYOUT PASSES, STYLE RECALCULATIONS, AND MULTIPLE PAINTS.
  94. HANDLING LARGE SETS OF DATA 😔 NON-PRACTICAL… ↝ FINDING PRIMES

    ↝ CRACKING PASSWORDS ↝ SIERPINSKI TRIANGLE 😊 PRACTICAL… ↝ RENDERING MANY DATA-POINTS ↝ RENDERING ON A <canvas> ↝ PROCESSING DATA
  95. HANDLING LARGE SETS OF DATA 😔 NON-PRACTICAL… ↝ FINDING PRIMES

    ↝ CRACKING PASSWORDS ↝ SIERPINSKI TRIANGLE 😊 PRACTICAL… ↝ RENDERING MANY DATA-POINTS ↝ RENDERING ON A <canvas> ↝ PROCESSING DATA
  96. ↝ ˜100K DATA POINTS PLOTTED ↝ SUPPORT FOR SEARCHING AND

    FILTERING. ↝ USED WORKERS + REDUX-SAGA UTILITIES + DEBOUNCING. ↝ COULD'VE USED TRANSITIONS. #1 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS LOCATION DATA
  97. ↝ THOUSANDS OF REAL-TIME PLAYERS MESSAGING. ↝ SUPPORT FOR SEARCHING

    AND FILTERING. ↝ USED VIRTUALIZATION AND MEMOIZATION. ↝ COULD'VE USED TRANSITIONS. REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS GAME ADMIN PANEL #2
  98. useSyncExternalStore function useSyncExternalStore<Snapshot>( subscribe: (onStoreChange: () = > void) =

    > () = > void, getSnapshot: () = > Snapshot, getServerSnapshot?: () = > Snapshot ): Snapshot;
  99. useLocation function Pathname() { const { pathname } = useLocation();

    return <Badge title={pathname} subtitle="pathname" />; } function Hash() { const { hash } = useLocation(); return <Badge title={hash} subtitle="hash" />; }
  100. useLocation function Pathname() { const { pathname } = useLocation();

    return <Badge title={pathname} subtitle="pathname" />; } function Hash() { const { hash } = useLocation(); return <Badge title={hash} subtitle="hash" />; } OVER-RETURNING HOOK
  101. useHistorySelector function useHistorySelector(selector) { const history = useHistory(); return useSyncExternalStore(history.listen,

    () = > selector(history)); } function Pathname() { const pathname = useHistorySelector((history) = > history.location.pathname); return <Badge title={pathname} subtitle="pathname" />; } function Hash() { const hash = useHistorySelector((history) = > history.location.hash); return <Badge title={hash} subtitle="hash" />; }
  102. useHistorySelector function useHistorySelector(selector) { const history = useHistory(); return useSyncExternalStore(history.listen,

    () = > selector(history)); } function Pathname() { const pathname = useHistorySelector((history) = > history.location.pathname); return <Badge title={pathname} subtitle="pathname" />; } function Hash() { const hash = useHistorySelector((history) = > history.location.hash); return <Badge title={hash} subtitle="hash" />; }
  103. …AND MUCH MORE! function subscribe(callback) { window.addEventListener('online', callback); window.addEventListener('offline', callback);

    return () = > { window.removeEventListener('online', callback); window.removeEventListener('offline', callback); }; } function getSnapshot() { return navigator.onLine; }
  104. …AND MUCH MORE! import { useSyncExternalStore } from 'react'; function

    OnlineStatus() { const isOnline = useSyncExternalStore( subscribe, getSnapshot, getSnapshot ); return ( <div className={isOnline ? 'online' : 'offline'}> {isOnline ? '🟢 Online' : '🔴 Offline'} </div> ); }
  105. ↝ NO PRIORITY CONTROL. ↝ NO CANCELLATION SEMANTICS. ↝ NO

    COORDINATION WITH THE BROWSER SCHEDULER. ↝ NO INPUT RESPONSIVENESS GUARANTEES. ↝ NO WAY TO BREAK LONG TASKS SAFELY. NATIVE SCHEDULING: CURRENT ISSUES
  106. ↝ SCHEDULE TASKS WITH EXPLICIT PRIORITY. ↝ COORDINATE WITH THE

    BROWSER RENDERING PIPELINE. ↝ REPLACE setTimeout( . . . , 0) HACKS. ↝ SUPPORTS CANCELLATION VIA SIGNALS. ↝ WORKS IN WORKERS TOO. SCHEDULE TASKS: OVERVIEW
  107. ↝ SPLIT LONG TASKS SAFELY. ↝ RETURN CONTROL TO THE

    BROWSER MID-EXECUTION. ↝ CONTINUE LATER WITH THE SAME PRIORITY. ↝ AVOID BLOCKING INPUT AND RENDERING. ↝ REPLACE MANUAL CHUNKING LOOPS. YIELDING: OVERVIEW
  108. PENDING INPUT: OVERVIEW while (workQueue.length > 0) { if (navigator.scheduling.isInputPending())

    { / / Stop doing work to handle any input event break; } let job = workQueue.shift(); job.execute(); }
  109. ↝ MANY PERFORMANCE OPTIMIZATIONS CAN BE MADE WHEN WE CAN

    PREDICT WHAT USERS MIGHT DO. ↝ THERE ARE A FEW SIMPLE BUT EFFECTIVE WAYS FOR DEVELOPERS TO HELP THE BROWSER STAY ONE STEP AHEAD OF THE USER AND KEEP PAGES FAST. PREDICT WORK
  110. ↝ PREDICT TAB NAVIGATION IN DASHBOARDS. ↝ PREFETCH THE NEXT

    ROUTE AFTER LOGIN SUCCESS. ↝ PRECONNECT ANALYTICS ENDPOINTS AFTER CONSENT. ↝ PRERENDER CHECKOUT AFTER CART INTERACTION. ↝ PREFETCH THE NEXT ARTICLE WHEN THE READER SCROLLS 75%. PREDICT WORK: IDEAS
  111. ↝ IT ALLOWS THE BROWSER TO SET UP EARLY CONNECTIONS

    BEFORE THE REQUEST IS ACTUALLY SENT TO THE SERVER. THIS INCLUDES: ↝ TLS NEGOTIATIONS ↝ TCP HANDSHAKES ↝ ELIMINATES ROUND-TRIP LATENCY. PRECONNECT: OVERVIEW
  112. PRECONNECT: OVERVIEW 100MS 200MS 300MS 400MS 500MS 600MS 700MS HTML

    CSS FONT 1 FONT 2 FONTS START LOADING FONTS RENDERED
  113. PRECONNECT: OVERVIEW 100MS 200MS 300MS 400MS 500MS 600MS 700MS HTML

    CSS FONT 1 FONT 2 FONTS START LOADING FONTS RENDERED FONT 1 FONT 2
  114. PRECONNECT: ↝ GOOGLE FONTS BEFORE CSS LOADS. ↝ THE API

    ORIGIN AFTER LOGIN SUCCESS. ↝ THE CDN HOSTING HERO IMAGE. ↝ THE ANALYTICS ENDPOINT AFTER CONSENT. ↝ THE CHECKOUT DOMAIN FROM THE PRODUCT PAGE. PRECONNECT: IDEAS
  115. ↝ DESIGNED TO IMPROVE PERFORMANCE FOR FUTURE DOCUMENT NAVIGATIONS. ↝

    A MODERN AND MORE EXPRESSIVE REPLACEMENT FOR OLDER PRERENDER TECHNIQUES. ↝ PREFETCH/PRERENDER DOCUMENTS AHEAD OF CLICKS. ↝ WORKS BEST FOR MPAS OR ROUTE-LEVEL TRANSITIONS. SPECULATION RULES: OVERVIEW
  116. SPECULATION RULES: OVERVIEW <script type="speculationrules"> { "prefetch": [{ "source": "list",

    "urls": ["/checkout"] }] } </script> <script type="speculationrules"> { "prerender": [{ "where": { "href_matches": "/product/ * " } }] } </script>
  117. ↝ PREFETCH /DASHBOARD AFTER LOGIN SUCCESS. ↝ PREFETCH /CHECKOUT AFTER

    CART INTERACTION. ↝ PREFETCH TOP RESULT LINKS IN THE VIEWPORT. ↝ PRERENDER LIKELY NEXT SETTINGS TAB. SPECULATION RULES: IDEAS
  118. ↝ TELL THE BROWSER WHAT MATTERS FIRST. ↝ OVERRIDE DEFAULT

    FETCH HEURISTICS WHEN NEEDED. ↝ OPTIMIZE LCP RESOURCES EXPLICITLY. PRIORITY HINTS: OVERVIEW
  119. PRIORITY HINTS: OVERVIEW < ! - - Increase the priority

    of the LCP image - - > <img src="image.jpg" fetchpriority="high" /> < ! - - Lower the priority of above-the-fold images - - > <ul class="carousel"> <img src="img/carousel-1.jpg" fetchpriority="high" /> <img src="img/carousel-2.jpg" fetchpriority="low" /> <img src="img/carousel-3.jpg" fetchpriority="low" /> </ul> < ! - - Reprioritize scripts - - > <script src="async_but_important.js" async fetchpriority="high"></script> <script src="blocking_but_unimportant.js" fetchpriority="low"></script>
  120. PRIORITY HINTS: OVERVIEW < ! - - Increase the priority

    of the LCP image - - > <img src="image.jpg" fetchpriority="high" /> < ! - - Lower the priority of above-the-fold images - - > <ul class="carousel"> <img src="img/carousel-1.jpg" fetchpriority="high" /> <img src="img/carousel-2.jpg" fetchpriority="low" /> <img src="img/carousel-3.jpg" fetchpriority="low" /> </ul> < ! - - Reprioritize scripts - - > <script src="async_but_important.js" async fetchpriority="high"></script> <script src="blocking_but_unimportant.js" fetchpriority="low"></script>
  121. PRIORITY HINTS: OVERVIEW / / Important validation data const user

    = await fetch("/user"); / / Less important content data const relatedPosts = await fetch("/posts/suggested", { priority: "low" });
  122. PRIORITY HINTS: OVERVIEW / / Important validation data const user

    = await fetch("/user"); / / Less important content data const relatedPosts = await fetch("/posts/suggested", { priority: "low" });
  123. ↝ BOOST HERO IMAGE PRIORITY. ↝ PRIORITIZE ROUTE TRANSITION BUNDLES.

    ↝ DEPRIORITIZE RECOMMENDATION PANELS. ↝ DEPRIORITIZE BELOW-FOLD IMAGES. ↝ CONTROL HYDRATION FETCH ORDERING. PRIORITY HINTS: IDEAS
  124. ↝ ZERO JAVASCRIPT. ↝ DEFER IMAGE AND IFRAME DOWNLOADS AUTOMATICALLY.

    ↝ LET THE BROWSER DECIDE OPTIMAL FETCH TIMING. ↝ REMOVE OFF-SCREEN CONTENT FROM THE CRITICAL RENDERING PATH. NATIVE LAZY LOADING: OVERVIEW
  125. NATIVE LAZY LOADING: OVERVIEW <img src="/gallery-1.jpg" loading="lazy" width="800" height="600" />

    <iframe src="https://maps.example.com" loading="lazy" width="600" height="400"> </iframe>
  126. ↝ PRODUCT GALLERY IMAGES. ↝ EMBEDDED YOUTUBE PLAYERS. ↝ MAPS

    AND CHAT WIDGETS. ↝ ANALYTICS DASHBOARDS BELOW THE FOLD. ↝ ROUTE-LEVEL IFRAMES IN MICRO-FRONTENDS. NATIVE LAZY LOADING: IDEAS
  127. “Lazy-loading iframes can lead to 2-3% median data savings, 1-2%

    FCP reductions, and 2% FID improvements at the 95th percentile.” Chrome team’s research • 2019
  128. ↝ RESTORE PAGES INSTANTLY ON BACK/FORWARD NAVIGATION. ↝ KEEP DOM

    + JAVASCRIPT HEAP ALIVE IN MEMORY. ↝ ELIMINATE RELOAD ENTIRELY. ↝ TURN NAVIGATION INTO RESTORATION. PRESERVE NAVIGATION: OVERVIEW
  129. PRESERVE NAVIGATION: MONITOR window.addEventListener('pageshow', (event) = > { if (event.persisted)

    { console.log('This page was restored from the bfcache.'); } else { console.log('This page was loaded normally.'); } });
  130. PRESERVE NAVIGATION: MONITOR window.addEventListener('pagehide', (event) = > { if (event.persisted)

    { console.log('This page might be entering the bfcache.'); } else { console.log('This page will unload normally and be discarded.'); } });
  131. PRESERVE NAVIGATION: MONITOR new PerformanceObserver(list = > { for (const

    entry of list.getEntries()) { console.log(entry.notRestoredReasons); } }).observe({ type: "navigation", buffered: true });
  132. ↝ ANIMATE TRANSITIONS BETWEEN DOM STATES. ↝ WORKS ACROSS SPA

    AND MPA NAVIGATION. ↝ MAINTAINS USER CONTEXT DURING CHANGE. ↝ REDUCES PERCEIVED LATENCY. SMOOTH NAVIGATION: OVERVIEW
  133. ↝ ANIMATE LIST → DETAIL NAVIGATION. ↝ SMOOTH DASHBOARD TAB

    SWITCHING. ↝ PRESERVE ELEMENT CONTINUITY BETWEEN ROUTES. ↝ REDUCE PERCEIVED LAYOUT SHIFT. ↝ MAKE MPAS FEEL LIKE NATIVE APPS. SMOOTH NAVIGATION: IDEAS
  134. PREACT: OVERVIEW ↝ WAY SMALLER BUNDLE (APPROXIMATELY 3.5KB). ↝ FASTER

    VIRTUAL DOM IMPLEMENTATION. ↝ MORE EFFECTIVE MEMORY USAGE.
  135. PREACT: CASE STUDY 205.9KB MIN + GZIP / NO POLYFILLS

    175.26KB MIN + GZIP / NO POLYFILLS
  136. INFORMED CODE SPLITTING const Video = lazy(() = > import("./Video"));

    const Preview = lazy(() = > import("./Preview")); const networkInfo = useNetworkStatus(); const { With, Switch, Otherwise } = usePatternMatch(networkInfo);
  137. INFORMED CODE SPLITTING <Suspense fallback={<div>Loading . . . </div>}> <With

    unsupported> <NetworkStatus networkInfo="unsupported" /> <Video /> </With> <With effectiveConnectionType="2g"> <NetworkStatus networkInfo="2g" /> <Preview /> </With> </Suspense>
  138. MEASURING OTHERS VISIBILITY STATE • INTERSECTION OBSERVER • LAYOUT INSTABILITY

    • CUSTOM METRICS PROFILING LONG TASKS • LONG ANIMATION FRAMES • SELF PROFILING • MEMORY USAGE TIMING USER TIMING • EVENT TIMING • RESOURCE TIMING • SERVER TIMING • ELEMENT TIMING SENSORS NETWORK STATUS • BATTERY STATUS • COMPUTE PRESSURE
  139. LONG TASKS: OVERVIEW new PerformanceObserver((list) = > { for (const

    entry of list.getEntries()) { console.log("Blocked for:", entry.duration); entry.attribution?.forEach((source) = > { console.log("Source:", source.containerSrc); }); } }).observe({ type: "longtask", buffered: true });
  140. DETECT: ↝ HYDRATION BLOCKING THE MAIN THREAD. ↝ LARGE BUNDLE

    EXECUTION PAUSES. ↝ THIRD-PARTY IFRAME BLOCKING INPUT. ↝ EXPENSIVE LAYOUT RECALCULATIONS. LONG TASKS: IDEAS
  141. DETECT: ↝ INP REGRESSIONS. ↝ RENDERING PIPELINE BOTTLENECKS. ↝ ANIMATION

    FRAME DROPS. ↝ SLOW CSS/LAYOUT RECALCULATIONS. ↝ SLOW COMPOSITING PHASES. LONG ANIMATION FRAMES: IDEAS
  142. SELF PROFILING: OVERVIEW const profiler = new Profiler({ sampleInterval: 10,

    maxBufferSize: 10000 }); await doWork(); const profile = await profiler.stop(); console.log(profile.samples);
  143. ↝ PROFILE REAL-WORLD HYDRATION BOTTLENECKS. ↝ PROFILE THIRD-PARTY SCRIPT EXECUTION

    TIME. ↝ DETECT HOT LOOPS IN DATA PROCESSING PIPELINES. ↝ DETECT REGRESSIONS AFTER FEATURE ROLLOUT. SELF PROFILING: IDEAS
  144. MEMORY USAGE: OVERVIEW const result = await performance.measureUserAgentSpecificMemory(); console.log("Total memory:",

    result.bytes); result.breakdown.forEach((entry) = > { console.log(entry.types, entry.bytes); });
  145. MEMORY USAGE: LEAKS #1 const obj = { a: new

    Array(1000), b: new Array(2000) }; setInterval(() = > { console.log(obj.a); }, 1000);
  146. MEMORY USAGE: LEAKS #4 const cache = new Map(); function

    track(el) { cache.set(el, new Array(100000).fill("data")); }
  147. ↝ FORGETTING TO UNREGISTER AN EVENT LISTENER. ↝ ACCIDENTALLY CAPTURING

    OBJECTS FROM AN IFRAME. ↝ NOT CLOSING A WORKER. ↝ ACCUMULATING OBJECTS IN ARRAYS. ↝ AND MUCH MORE! MEMORY USAGE: LEAKS
  148. ↝ DETECT MEMORY LEAKS AFTER ROUTE TRANSITIONS. ↝ DETECT IFRAME

    MEMORY ISOLATION ISSUES. ↝ DETECT DOM NODE ACCUMULATION REGRESSIONS. ↝ MEASURE SPA CACHE GROWTH OVER TIME. ↝ COMPARE THE MEMORY COST OF FEATURE VARIANTS. MEMORY USAGE: IDEAS
  149. ↝ MAIN-THREAD BLOCKING ↝ WHERE TIME GOES. ↝ FRAME PIPELINE

    BLOCKING ↝ WHERE FRAMES DROP. ↝ CPU HOTSPOT ATTRIBUTION ↝ WHAT CODE RUNS. ↝ MEMORY HOTSPOT ATTRIBUTION ↝ WHERE MEMORY GROWS. PROFILING
  150. ↝ DISABLE ROUTE PREFETCHING ON SLOW CONNECTIONS. ↝ SKIP ANALYTICS

    UPLOADS WHEN RTT IS HIGH. ↝ LOAD LOWER-RESOLUTION ON CONSTRAINED BANDWIDTH. ↝ ADAPT TO SITUATIONS WHEN USERS ARE OFFLINE. ↝ RESPECT DATA SAVING AS A USER PERFORMANCE PREFERENCE SIGNAL. NETWORK STATUS: IDEAS
  151. NETWORK STATUS: IDEAS switch (connectionType) { case "4g": return <Video

    src={videoSrc} />; case "3g": return <Image src={imageSrc.hiRes} alt={alt} />; default: return <Image src={imageSrc.lowRes} alt={alt} />; }
  152. BATTERY STATUS: OVERVIEW const batteryInfo = await navigator.getBattery(); batteryInfo.addEventListener("chargingchange", listener);

    batteryInfo.addEventListener("chargingtimechange", listener); batteryInfo.addEventListener("dischargingtimechange", listener); batteryInfo.addEventListener("levelchange", listener);
  153. ↝ DISABLE BACKGROUND POLLING ON LOW BATTERY. ↝ REDUCE ANIMATION

    FREQUENCY. ↝ STOP PREFETCHING BUNDLES. ↝ PERSIST UNSAVED DATA BEFORE SHUTDOWN RISK. ↝ SWITCH TO A STATIC MAP RATHER THAN AN INTERACTIVE ONE. BATTERY STATUS: IDEAS
  154. COMPUTE PRESSURE: OVERVIEW const observer = new PressureObserver(records = >

    { const state = records[0].state; if (state === "critical") { reduceRenderingQuality(); } }); observer.observe("cpu", { sampleInterval: 2000 });
  155. ↝ LOWER CANVAS RESOLUTION DYNAMICALLY. ↝ PAUSE BACKGROUND DATA PROCESSING

    PIPELINES. ↝ SWITCH FROM REAL-TIME UPDATES TO BATCHED ONES. ↝ DROP FRAME RATE IN WEBGL SCENES. ↝ REDUCE ANIMATION QUALITY WHEN CPU PRESSURE RISES. COMPUTE PRESSURE: IDEAS
  156. PAGE VISIBILITY: OVERVIEW document.hidden; document.visibilityState; document.addEventListener("visibilitychange", () = > {

    if (document.visibilityState===“hidden") { console.log("This window is hidden") } else { console.log("This window is visible") } })
  157. ↝ CANCEL POLLING LOOPS, TIMERS, AND BACKGROUND NETWORK REFRESHES WHEN

    THE TAB BECOMES HIDDEN. ↝ PAUSE VIDEO, AUDIO, AND ANIMATION LOOPS WHEN THE USER ISN’T ACTIVELY WATCHING THE PAGE. ↝ RESUME PROGRESSIVE DOWNLOADS OR DYNAMIC IMPORTS WHEN THE PAGE BECOMES VISIBLE AGAIN. PAGE VISIBILITY: IDEAS
  158. ↝ STOP REFRESHING DASHBOARDS OR LIVE DATA FEEDS WHILE THE

    TAB IS BACKGROUNDED. ↝ SEND ANALYTICS RELIABLY AT SESSION END WHEN VISIBILITY BECOMES HIDDEN. ↝ SILENCE NOTIFICATIONS OR SOUNDS WHEN THE DEVICE SCREEN LOCKS OR THE TAB LOSES VISIBILITY. PAGE VISIBILITY: IDEAS
  159. INTERSECTION OBSERVER: OVERVIEW const onIntersection = (entries) = > {

    for (const entry of entries) { if (entry.isIntersecting) { console.log(entry); } } }; const observer = new IntersectionObserver(onIntersection); observer.observe(document.querySelector('#target'));
  160. ↝ INITIALIZE EXPENSIVE RENDERING PIPELINES (CHARTS, CANVAS, WEBGL) ONLY WHEN

    NEEDED. ↝ LAZY-LOAD IMAGES, IFRAMES, AND ROUTE BUNDLES WHEN THEY APPROACH THE VIEWPORT. ↝ DELAY LOADING THIRD-PARTY WIDGETS (MAPS, VIDEO EMBEDS, CHAT CLIENTS) UNTIL VISIBLE. ↝ CONTROL MEDIA PLAYBACK DEPENDING ON VISIBILITY. INTERSECTION OBSERVER: IDEAS
  161. ↝ RENDER/HYDRATE COMPLEX UI COMPONENTS ONLY WHEN THEY BECOME RELEVANT.

    ↝ TRIGGER ANALYTICS EVENTS WHEN USERS ACTUALLY SEE IMPORTANT UI SECTIONS. ↝ MEASURE HOW LONG ELEMENTS REMAIN VISIBLE (E.G., AD IMPRESSIONS). INTERSECTION OBSERVER: IDEAS
  162. ↝ MANY WEBSITES HAVE DOM ELEMENTS SHIFTING AROUND DUE TO

    CONTENT LOADING ASYNCHRONOUSLY. ↝ MEASURE REAL CLS VALUES IN PRODUCTION. ↝ IDENTIFY THE EXACT DOM ELEMENTS RESPONSIBLE FOR LAYOUT INSTABILITY. ↝ IGNORE EXPECTED SHIFTS CAUSED BY USER INTERACTION. LAYOUT INSTABILITY: OVERVIEW
  163. LAYOUT INSTABILITY: OVERVIEW let cls = 0; new PerformanceObserver((list) =

    > { for (const entry of list.getEntries()) { if (entry.hadRecentInput) continue; / / ignore expected shifts cls += entry.value; const culprit = entry.sources?.[0]?.node; console.log("Shift:", entry.value); console.log("Element:", culprit); console.log("CLS so far:", cls); } }).observe({ type: "layout-shift", buffered: true });
  164. ↝ DETECT INSTABILITY INTRODUCED BY THIRD-PARTY EMBEDS OR PERSONALIZATION. ↝

    DETECT IMAGES OR IFRAMES LOADING WITHOUT A RESERVED SPACE. ↝ DETECT LAYOUT SHIFTS CAUSED BY WEB-FONT SWAPS. LAYOUT INSTABILITY: IDEAS
  165. #protip 💡 Existing RUM and DXA tools are great—until scale,

    cost, or product-speci fi c questions force you to measure things yourself.
  166. TIME UNTIL THE… ↝ SCROLL EFFECTS WORK. ↝ APP RESPONDS

    TO CLICKS. ↝ MOST MEANINGFUL VIDEOS/ANIMATIONS RUN. ↝ PRIMARY FEATURE SHOWS UP/IS INTERACTIVE. ↝ COOKIE BANNER SHOWS UP. PRODUCT-SPECIFIC QUESTIONS
  167. Understanding these internals and their rationales helps us implement our

    own abstractions. #1 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  168. AI agents can write React. But engineers who understand scheduling,

    rendering, and data- fl ow boundaries can decide what should be optimized. #1 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  169. React tries to address the lack of some JavaScript/Web Platform

    resources. #3 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  170. Core Web Vitals are a better starting point than a

    fi nish line. #4 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS — IN THE BLINK OF AN EYE • TIM KADLEC , 2024
  171. There's no silver bullet. Identify your core metrics. #5 REACT:

    INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  172. #6 Always try to correlate behavior analysis with contextual metrics

    and business outcomes to tell the full story. REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  173. #7 Don't take fast networks, CPUs and RAM for granted.

    REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS
  174. There's probably a business case for making your app faster.

    But web performance is about more than “just” business. #9 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS