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

๐Ÿ‡ฌ๐Ÿ‡ง CityJS London 2025 (Workshop)

๐Ÿ‡ฌ๐Ÿ‡ง CityJS London 2025ย (Workshop)

React: Internals and Advanced Performance Patterns

Writing fluid user interfaces becomes increasingly challenging as the application complexity increases. Also, in a world with a wide variety of network connections, any user can have a slow experience, and apps that delight users on fast connections can barely be usable on slow ones.

With a methodology based mostly on:

โ† Revisiting Computer Science concepts.

โ† Understanding how tools work under the hood and the rationales behind that by checking their source code.

โ† Leveraging real-world case studies from small, medium, and enterprise-scale companies.

In this workshop, we will address the following topics:

โ† Scheduling, reconciliation, React Fiber, and concurrent React features.

โ† Static analysis, compilers, the React compiler, and Million.js.

โ† Different rendering patterns, like islands, streaming SSR, and React Server Components.

โ† A wide range of native, performance-related, browser APIs.

โ† Measuring responsiveness, and reliably identifying culprits for bad experiences.

โ† Apply modern techniques to legacy codebases, via code generation, polyfilling, and others.

Matheus Albuquerque

April 24, 2025
Tweet

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. REAL-WORLD REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS โ€ข APRIL 24,

    2025. Hello, London! ๐Ÿ‘‹ ๐Ÿ‡ฌ๐Ÿ‡ง
  2. Matheus Albuquerque โ† ๐Ÿ‘จ๐Ÿ’ป Staff SWE @ Medallia โ† โš›

    Chair @ React Su m m it NYC โ† โšก Google Developer Expert โ† ๐• ythecombinator
  3. #question ๐Ÿค” Who here works with front-end? And React? REACT:

    INTERNALS AND ADVANCED PERFORMANCE PATTERNS/
  4. REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS/ Which browsers are visiting

    our app? โ€”โ€‰APP DYNAMICS REPORT โ€ข 2022
  5. #research ๐Ÿ“š 40% of Brits reported that they had become

    physically violent toward their computers. โ€”โ€‰British Psychology Society โ€ข 2009
  6. #research ๐Ÿ“š A 500ms delay resulted in up to a

    26% increase in frustration and up to an 8% decrease in engagement. โ€”โ€‰Radware โ€ข 2013
  7. #research ๐Ÿ“š 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
  8. #research ๐Ÿ“š 53% of mobile users abandon sites that take

    over 3 seconds to load. โ€”โ€‰DoubleClick โ€ข 2020
  9. โ€œ[โ€ฆ] With React you can build applications without even thinking

    about performance and the default state is fast.โ€ โ€”โ€‰Rethinking Best Practices โ€ข Pete Hunt, 2013
  10. โ€œFASTโ€ PERCEIVED LOAD SPEED HOW QUICKLY A PAGE CAN LOAD

    AND RENDER ALL OF ITS VISUAL ELEMENTS TO THE SCREEN LOAD RESPONSIVENESS HOW QUICKLY A PAGE CAN LOAD/RUN ANY REQUIRED JS IN ORDER FOR COMPONENTS TO RESPOND TO USER INTERACTION RUNTIME RESPONSIVENESS AFTER THE PAGE LOAD, HOW QUICKLY CAN THE PAGE RESPOND TO USER INTERACTION? SMOOTHNESS DO TRANSITIONS & ANIMATIONS RENDER AT A CONSISTENT FRAME RATE AND FLOW FLUIDLY?
  11. PERF MITIGATORS: โ† shouldComponentUpdate, React.PureComponent โ† React.memo โ† useMemo, useCallback

    โ† useTransition, useDeferredValue, React.Suspense & others! MAKING THINGS โ€œFASTโ€
  12. [โ€ฆ] โ€œ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
  13. [โ€ฆ] โ€œ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
  14. Weโ€™ll not focus onโ€ฆ โ† ISG, SSR, Streaming SSRโ€ฆ โ†

    Progressive/Selective/Partial Hydrationโ€ฆ โ† Islands Architecture, Resumabilityโ€ฆ
  15. 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
  16. โ† 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 + RESULTS. METHODOLOGY
  17. 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 โ€ข Me, 2025
  18. METHODOLOGY: TOPICS #1 SCHEDULING CS RECAP โ€ข SCHEDULING (LONG TASKS,

    RUNNING STRATEGIES) โ€ข IN REACT + ON THE WEB #2 COMPILERS REACT COMPILER โ€ข MILLION โ€ข CASE STUDIES #3 MEASURING TIMING โ€ข PROFILING โ€ข SENSORS โ€ข CUSTOM METRICS #4 OTHER TECHNIQUES RESOURCE HINTS โ€ข PRIORITY HINTS โ€ข LAZY-LOADING โ€ข PREACT โ€ข WINDOWING
  19. โ† CLONING THE REPO NOW. โ† GETTING THE SLIDES LATER.

    โ† QUESTIONS AT THE END OF EACH SECTION. โ† 15 MINUTES BREAK. METHODOLOGY
  20. 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
  21. THIS SECTION PRESENTSโ€ฆ #6 SCHEDULING ON THE WEB OVERVIEW โ€ข

    NATIVE SCHEDULING API #5 SCHEDULING IN REACT OVERVIEW โ€ข HEURISTICS โ€ข PRIORITY LEVELS โ€ข RENDER LANES โ€ข USE CASES
  22. 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)
  23. 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, }, }
  24. 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.
  25. 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.
  26. 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.
  27. 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.
  28. 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.
  29. 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
  30. โ€œ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
  31. HOMOICONICITY (let [x 1] (inc x)) ; = > 2

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

    INCREMENTS X TO GIVE THE RETURN VALUE OF 2
  33. 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
  34. 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)
  35. โ† REACT ELEMENTS ARE JUST DATA. โ† JUST LIKE IN

    LISP, REACT COMPONENTS CAN MANIPULATE THEIR CHILDREN AND RETURN COMPLETELY DIFFERENT THINGS. HOMOICONICITY + REACT
  36. โ€œ[โ€ฆ] 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
  37. PATTERN MATCHING factorial : : (Integral a) = > a

    - > a factorial 0 = 1 factorial n = n * factorial (n - 1)
  38. 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 =
  39. 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 > > ; } / / . . .
  40. 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 > > ; } / / . . .
  41. 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> ); }
  42. 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.
  43. 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.
  44. 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
  45. โ† 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
  46. โ† 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
  47. โ† 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
  48. โ† 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
  49. โ† 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
  50. โ† 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
  51. 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.
  52. 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.
  53. 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.
  54. 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.
  55. EFFECT HANDLERS: EFF (* state.eff *) type user = string

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

    * int effect Get: user effect Set: user - > unit A USER WITH A NAME AND AGE.
  57. 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.
  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) ;;
  59. 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.
  60. 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.
  61. 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.
  62. 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.
  63. 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'; } }
  64. 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'; } }
  65. 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.
  66. 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.
  67. LAYOUT ALGORITHM THE REACT TEAM APPARENTLY SPENT SOME TIME EXPERIMENTING

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

    AND ADVANCED PERFORMANCE PATTERNS/
  69. 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) ); }
  70. 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
  71. 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.
  72. 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.
  73. 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.
  74. 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.
  75. TASKS A UNIT OF WORK THAT THE BROWSER DOES TO

    RENDER A FRAME. JAVASCRIPT STYLES LAYOUT PAINT COMPOSITE
  76. 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.
  77. #question ๐Ÿค” How to avoid blocking the main thread? REACT:

    INTERNALS AND ADVANCED PERFORMANCE PATTERNS/
  78. 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.
  79. 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.
  80. 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.
  81. 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.
  82. 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.
  83. WEB WORKERS: ACTORS โ† MOST OF THE APIS ARE BUILT

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

    THREADING MODEL OF C++ AND OTHERS. โ† 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.
  85. 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.
  86. WORKERS โ† GOOD FOR DATA PROCESSING AND CRUNCHING NUMBERS. โ†

    HARD TO USE FOR UI-RELATED STUFF. โ† HARDER THAN ADJUSTING IT FOR A SCHEDULER.
  87. 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
  88. 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
  89. 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
  90. 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.
  91. HEURISTICS โ†“ ORIGINAL RENDER TASK USER INPUT โ†’ โ†‘ HIGHER

    PRIORITY RENDER TASK โ†“ RESUME ORIGINAL RENDER TASK
  92. 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.
  93. 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)
  94. 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.
  95. 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.
  96. HANDLING LARGE SETS OF DATA ๐Ÿ˜” NON-PRACTICALโ€ฆ โ† FINDING PRIMES

    โ† CRACKING PASSWORDS โ† SIERPINSKI TRIANGLE ๐Ÿ˜Š PRACTICALโ€ฆ โ† RENDERING MANY DATA-POINTS โ† RENDERING ON A <canvas> โ† PROCESSING DATA
  97. HANDLING LARGE SETS OF DATA ๐Ÿ˜” NON-PRACTICALโ€ฆ โ† FINDING PRIMES

    โ† CRACKING PASSWORDS โ† SIERPINSKI TRIANGLE ๐Ÿ˜Š PRACTICALโ€ฆ โ† RENDERING MANY DATA-POINTS โ† RENDERING ON A <canvas> โ† PROCESSING DATA
  98. โ† หœ100K DATA POINTS PLOTTED โ† SUPPORT FOR SEARCHING AND

    FILTERING. โ† USED WORKERS + REDUX-SAGA UTILITIES + DEBOUNCING. โ† COULD'VE USED TRANSITIONS. LOCATION DATA #1 of 2 REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS/
  99. GAME ADMIN PANEL REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS/ โ†

    THOUSANDS OF REAL-TIME PLAYERS MESSAGING. โ† SUPPORT FOR SEARCHING AND FILTERING. โ† USED VIRTUALIZATION AND MEMOIZATION. โ† COULD'VE USED TRANSITIONS. #2 of 2
  100. useSyncExternalStore function useSyncExternalStore<Snapshot>( subscribe: (onStoreChange: () = > void) =

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

    return <Badge title={pathname} subtitle="pathname" />; } function Hash() { const { hash } = useLocation(); return <Badge title={hash} subtitle="hash" />; }
  102. 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
  103. 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" />; }
  104. 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" />; }
  105. SCHEDULING ON THE WEB WE HAVE A FEW SCHEDULING PRIMITIVES:

    โ† setTimeout โ† requestAnimationFrame โ† requestIdleCallback โ† postMessage
  106. SCHEDULING ON THE WEB โ† WE ALL SHOULD USE THE

    SAME SCHEDULER. โ† HAVING MORE THAN ONE SCHEDULER CAUSES RESOURCE FIGHTING. โ† INTERLEAVING TASKS WITH BROWSER WORK (RENDERING, GARBAGE COLLECTION, ETC.).
  107. SCHEDULING API โ† A MORE ROBUST SOLUTION FOR SCHEDULING TASKS.

    โ† INTEGRATED DIRECTLY INTO THE EVENT LOOP. โ† CONTROL AND SCHEDULE PRIORITIZED TASKS IN A UNITED AND FLEXIBLE WAY. โ† ALIGNED WITH THE WORK OF THE REACT TEAM AND IN COOPERATION WITH GOOGLE, W3C AND OTHERS.
  108. SCHEDULING API scheduler.postTask() SCHEDULE AND CONTROL PRIORITIZING TASKS. scheduler.wait() YIELD

    AND RESUME AFTER SOME AMOUNT OF TIME OR PERHAPS AFTER AN EVENT HAS OCCURRED. scheduler.yield() BREAK UP LONG TASKS BY YIELDING TO THE BROWSER AND CONTINUING AFTER BEING RESCHEDULED. isInputPending() DETERMINE IF THE CURRENT TASK IS BLOCKING INPUT EVENTS.
  109. SCHEDULING API: isInputPending while (workQueue.length > 0) { if (navigator.scheduling.isInputPending())

    { / / Stop doing work to handle any input event break; } let job = workQueue.shift(); job.execute(); }
  110. #protip ๐Ÿ’ก Code that yields too often can cause the

    overhead of scheduling tasks to become a negative in fl uence on your appโ€™s overall performance.
  111. THIS SECTION PRESENTSโ€ฆ #1 INTRODUCTION MOTIVATION โ€ข COMPILERS & STATIC

    ANALYSIS #2 REACT COMPILER OVERVIEW โ€ข WHAT THE COMPILER DOES โ€ข WHAT THE COMPILER DOES NOT DO #3 MILLION MILLION LINT โ€ข MILLION.JS #4 COMPILERS FOR US TREE SHAKING โ€ข UPGRADING REACT โ€ข MIGRATING FROM JQUERY
  112. โ€œSo hereโ€™s my advice for anyone who wants to make

    a dent in the future of web development: time to learn how compilers work.โ€ Compilers are the New Frameworks โ€ข Tom Dale, 2017
  113. COMPILERS & STATIC ANALYSISโ€ฆ โ† LINTERS: ESLint (2013), TSLint (2015),

    Biome (2023), Oxlint (2023)โ€ฆ โ† FORMATTERS: Prettier (2017), dprint (2020), Biome (2023)โ€ฆ โ† BUNDLERS: Webpack (2012), Rollup (2015), Vite (2020), esbuild (2020), Rspack (2022), Rolldown (2023)โ€ฆ
  114. COMPILERS & STATIC ANALYSISโ€ฆ โ† TRANSPILERS: Babel (2014), SWC (2020)โ€ฆ

    โ† TYPE CHECKERS: TypeScript (2012), Flow (2014)โ€ฆ โ† MINIFIERS: UglifyJS (2010), Terser (2018)โ€ฆ โ† CSS PROCESSING & OPTIMIZATION: PostCSS (2013), CSSO (2015), cssnano (2015), LightningCSS (2022)โ€ฆ
  115. โ€œReactive systems have existed even in this space for years.

    In fact, reactivity was seen as a bad thing for a while with the rise of the popularity of React. The thing that has made reactive programming interesting again are compilers.โ€ Marko: Compiling Fine-Grained Reactivity โ€ข Ryan Carniato, 2022
  116. โ€œStatic analysis and compilation let us take what we know

    of your code's structure and optimize the creation paths as we already know what you are trying to create. We can see what parts of the template are static. We can infer from where dynamic sections are used how to run the most optimal code.โ€ Marko: Compiling Fine-Grained Reactivity โ€ข Ryan Carniato, 2022
  117. REACT COMPILER โ† IMPROVE THE RENDERING PERFORMANCE BY AUTOMATICALLY GENERATING

    THE EQUIVALENT OF useMemo, useCallback, AND memo CALLS. โ† MINIMIZE THE COST OF RE-RENDERING WHILE RETAINING REACTโ€™S PROGRAMMING MODEL. โ† AUTOMATIC OPTIMIZATION COMPILER.
  118. EXPENSIVE COMPONENTS function App() { return items.map((item) = > (

    <> <ExpensiveComponent text={item.text} /> <div>Not Expensive</div> </> )); }
  119. EXPENSIVE COMPONENTS function App() { return items.map((item) = > (

    <> {useMemo( () = > ( <ExpensiveComponent text={item.text} /> ), [item.text], )} <div>Not Expensive</div> </> )); }
  120. EXPENSIVE OPERATIONS function App() { const num = useMemo(() =

    > computeFibonacci(100), []); return <div>{num}</div>; }
  121. OBJECTS THAT RECREATE ON RENDER function Parent() { const [data,

    setData] = useState([]); return <ChildComponent state={{ data, setData }} />; }
  122. OBJECTS THAT RECREATE ON RENDER function Parent() { const [data,

    setData] = useState([]); return <ChildComponent state={useMemo(() = > ({ data, setData }), [data])} />; }
  123. ALIAS ANALYSIS โ† TWO COMMON KINDS OF POINTER ANALYSIS ARE

    ALIAS ANALYSIS AND POINTS-TO ANALYSIS. โ† IT'S USED TO DETERMINE IF VARIABLES (OR MEMORY LOCATIONS) REFER TO THE SAME UNDERLYING DATA. โ† IT HELPS COMPILERS OPTIMIZE CODE BY REORDERING INSTRUCTIONS, ELIMINATING REDUNDANT CALCULATIONS AND AVOIDING UNINTENDED SIDE EFFECTS.
  124. ALIAS ANALYSIS function example(arr) { arr[0] = 10; const value

    = arr[0]; return value; } DOES `VALUE` ALWAYS EQUAL 10?
  125. ALIAS ANALYSIS: EXAMPLE #1 function Component({ a, b }) {

    const x = []; x.push(a); return <Foo x={x} />; } function Component({ a, b }) { > = }
  126. function Component({ a, b }) { = } function Component({

    a, b }) { const x = useMemo(() = > { const x = []; x.push(a); return x; }, [a]); return <Foo x={x} />; } ALIAS ANALYSIS: EXAMPLE #1
  127. function Component({ a, b }) { const x = [];

    x.push(a); const y = x; y.push(b); return <Foo x={x} />; } function Component({ a, b }) { > = > = } ALIAS ANALYSIS: EXAMPLE #2
  128. function Component({ a, b }) { = = } function

    Component({ a, b }) { const x = useMemo(() = > { const x = []; x.push(a); return x; }, [a]); const y = useMemo(() = > { const y = x; y.push(b); return y; }, [x, b]); return <Foo x={x} />; } ALIAS ANALYSIS: EXAMPLE #2
  129. function Component({ a, b }) { const x = [];

    x.push(a); const y = x; y.push(b); return <Foo x={x} />; } function Component({ a, b }) { > = > = } โŒ ALIAS ANALYSIS: EXAMPLE #2
  130. function Component({ a, b }) { = = } function

    Component({ a, b }) { const x = useMemo(() => { const x = []; x.push(a); const y = x; y.push(b); return y; }, [a, b]); return <Foo x={x} />; } ALIAS ANALYSIS: EXAMPLE #2
  131. GOTCHAS #1: DEPENDENCIES ARRAY const Component = ({currentValue, onValueChange}) =

    > { useEffect(() = > { onValueChange(currentValue) }, currentValue); };
  132. GOTCHAS #1: REF ACCESS export default function usePrevious<T>(state: T): T

    | undefined { const ref = useRef<T>(); useEffect(() = > { ref.current = state; }); return ref.current; }
  133. GOTCHAS #3: COMPUTED KEYS const [currentLevel, setCurrentLevel] = useState(difficulty) const

    useRatingSystem = (props: RecipeProps) = > { return { [props.difficulty]: "โญ".repeat(props.difficulty === 'easy' ? 1 : props.difficulty === 'medium' ? 2 : 3) } } const rating = useRatingSystem({ difficulty: currentLevel })
  134. const [currentLevel, setCurrentLevel] = useState(difficulty) const useRatingSystem = (props: RecipeProps)

    = > { return { [props.difficulty]: "โญ".repeat(props.difficulty === 'easy' ? 1 : props.difficulty === 'medium' ? 2 : 3) } } const rating = useRatingSystem({ difficulty: currentLevel }) GOTCHAS #3: COMPUTED KEYS
  135. MILLION LINT: COMPILER function App({ start }) { const [count,

    setCount] = useState(start); useEffect(() = > { console.log("double: ", count * 2); }, [count]); return <Button onClick={() = > setCount(count + 1)}>{count}</Button>; }
  136. MILLION LINT: COMPILER function App({ start }) { Million.capture({ start

    }); const [count, setCount] = Million.capture(useState)(start); useEffect( () = > { console.log("double: ", count * 2); }, Million.capture([count]), ); return Million.capture( <Button onClick={() = > setCount(count + 1)}>{count}</Button>, ); }
  137. MILLION LINT: COMPILER [ 'src/App.jsx': { components: { App: {

    renders: [{ count: 7, time: 0.1 }, . . . ], instances: 3, count: 70, time: 1, location: [13, 0, 23, 1], } } } ]; [ { kind: 'state', count: 7, time: 0.1, changes: [{ prev: 0, next: 8 }, . } ];
  138. MILLION LINT: COMPILER [ 'src/App.jsx': { components: { App: {

    renders: [{ count: 7, time: 0.1 }, . instances: 3, count: 70, time: 1, location: [13, 0, 23, 1], } } } ]; [ { kind: 'state', count: 7, time: 0.1, changes: [{ prev: 0, next: 8 }, . . . ], } ];
  139. #definition ๐Ÿง jscodeshift is a tool that runs a transformation

    script over one or more JavaScript or TypeScript fi les.
  140. export default function transformer(file: FileInfo, api: API) { const j

    = api.jscodeshift; const root = j(file.source); const variableDeclarators = root.findVariableDeclarators('foo'); variableDeclarators.renameTo('bar'); return root.toSource(); } REACT 15 โ† 16: AST
  141. THIS SECTION PRESENTSโ€ฆ #1 TIMING USER TIMING โ€ข ELEMENT TIMING

    โ€ข EVENT TIMING โ€ข RESOURCE TIMING โ€ข NAVIGATION TIMING โ€ข SERVER TIMING #3 SENSORS BATTERY STATUS โ€ข NETWORK INFORMATION #2 PROFILING LONG TASKS API โ€ข USERAGENT SPECIFIC MEMORY โ€ข JAVASCRIPT SELF-PROFILING API #4 CUSTOM METRICS USER FRUSTRATION โ€ข MONITORING THIRD-PARTIES
  142. USER TIMING / / Record the time i m m

    ediately before running a task performance.mark('myTask:start'); await doMyTask(); / / Record the time i m m ediately after running a task performance.mark('myTask:end'); / / Measure the delta between the start and end of the task performance.measure('myTask', 'myTask:start', โ€˜myTask:end'); observer.observe({type: 'measure'});
  143. USER TIMING: TOOLS โ€” "USER TIMING AND CUSTOM METRICS" BY

    STEVE SOUDERS โ€” "USER TIMING AND CUSTOM METRICS" BY STEVE SOUDERS
  144. ELEMENT TIMING โ† ALLOWS YOU TO MEASURE THE RENDER TIME

    OF SPECIFIC ELEMENTS. โ† USEFUL FOR KNOWING WHEN THE LARGEST IMAGE OR TEXT BLOCK WAS PAINTED TO THE SCREEN. โ† THE BASIS FOR THE LARGEST CONTENTFUL PAINT (LCP) METRIC.
  145. EVENT TIMING โ† USEFUL TO MEASURE THE EVENT PROCESSING TIME

    AS WELL AS THE TIME UNTIL THE NEXT FRAME CAN BE RENDERED. โ† EXPOSES A NUMBER OF TIMESTAMPS IN THE EVENT LIFECYCLE. โ† THE BASIS FOR THE FIRST INPUT DELAY METRIC.
  146. EVENT TIMING MEASURE THE LATENCYโ€ฆ โ† FROM A CLICK UNTIL

    WE REORDER CONTENT ON A TABLE. โ† TO DRAG A SLIDER TO FILTER SOME DATA. โ† FOR A FLYOUT TO APPEAR WHEN HOVERING A MENU ITEM.
  147. EVENT TIMING const observer = new PerformanceObserver((entryList) = > {

    const firstInput = entryList.getEntries()[0]; const firstInputDelay = firstInput.processingStart - firstInput.startTime; / / Measure the time it takes to run all event handlers const firstInputProcessingTime = firstInput.processingEnd - firstInput.processingStart; / / Measure the entire duration of the event const firstInputDuration = firstInput.duration; }); observer.observe({type: 'first-input'});
  148. RESOURCE TIMING const observer = new PerformanceObserver((list) = > {

    for (const entry of list.getEntries()) { / / If transferSize is 0, the resource was fulfilled via the cache. console.log(entry.name, entry.transferSize === 0); } }); observer.observe({type: 'resource'});
  149. NAVIGATION TIMING const observer = new PerformanceObserver((list) = > {

    for (const entry of list.getEntries()) { console.log('Time to first byte', entry.responseStart); } }); observer.observe({type: 'navigation'});
  150. NAVIGATION TIMING / / ServiceWorker startup time const workerStartupTime =

    entry.responseStart - entry.workerStart; / / Request time only (excluding redirects, DNS, and connection/TLS time) const requestTime = entry.responseStart - entry.requestStart; / / Response time only (download) const responseTime = entry.responseEnd - entry.responseStart; / / Request + response time const requestResponseTime = entry.responseEnd - entry.requestStart;
  151. SERVER TIMING MEASURE ANY WORK THAT THE SERVER DOES TO

    COMPLETE A REQUEST: โ† ROUTING/AUTHENTICATING THE REQUEST. โ† RUNNING CONTENT THROUGH TEMPLATING SYSTEMS. โ† QUERYING DATABASES/API CALLS TO THIRD-PARTY SERVICES.
  152. LONG TASKS โ† REPORTS TASKS THAT TAKES LONGER THAN 50

    MS. โ† USEFUL TO TRACK WHEN THE BROWSER'S MAIN THREAD IS BLOCKED. โ† THE BASIS FOR TIME TO INTERACTIVE (TTI) AND TOTAL BLOCKING TIME (TBT) METRICS.
  153. LONG TASKS observer.observe({type: 'longtask'}); { name: "same-origin-descendant", entryType: "longtask", startTime:

    1023.40999995591, duration: 187.19000002602115, attribution: [ { name: "unknown", entryType: "taskattribution", startTime: 0, duration: 0, containerType: "iframe", containerSrc: "child.html", containerId: "", containerName: "child1" } ] };
  154. JS SELF-PROFILING API const profiler = new Profiler({ sampleInterval: 10,

    maxBufferSize: 10000 }); / / Do work . . . const trace = await profiler.stop(); sendProfile(trace);
  155. JS SELF-PROFILING API โ† PROFILE SPECIFIC COMPLEX OPERATIONS. โ† PROFILE

    THIRD-PARTY SCRIPTS. โ† COMBINE WITH OTHER EVENTS/IMPORTANT METRICS, LIKE LONG TASKS OR EVENT TIMING APIS.
  156. USERAGENT SPECIFIC MEMORY โ† MEASURES THE MEMORY USAGE AND DETECTS

    MEMORY LEAKS. โ† WAITS FOR THE NEXT GC AND THEN MEASURES MEMORY IMMEDIATELY AFTER THE UNNEEDED MEMORY HAS BEEN RELEASED. โ† FORCES GC IF IT DOES NOT HAPPEN FOR 20S.
  157. MEMORY LEAKS โ† FORGETTING TO UNREGISTER AN EVENT LISTENER. โ†

    ACCIDENTALLY CAPTURING OBJECTS FROM AN IFRAME. โ† NOT CLOSING A WORKER. โ† ACCUMULATING OBJECTS IN ARRAYS.
  158. MEMORY LEAKS const obj = { a: new Array(1000), b:

    new Array(2000) }; setInterval(() = > { console.log(obj.a); }, 1000);
  159. BATTERY STATUS const batteryInfo = await navigator.getBattery(); batteryInfo.addEventListener("chargingchange", listener); batteryInfo.addEventListener("chargingtimechange",

    listener); batteryInfo.addEventListener("dischargingtimechange", listener); batteryInfo.addEventListener("levelchange", listener);
  160. NETWORK INFORMATION โ† SWITCH BETWEEN SERVING HIGH/LOW DEFINITION CONTENT BASED

    ON THE USER'S NETWORK. โ† DECIDE WHETHER TO PRELOAD RESOURCES. โ† DEFER UPLOADS/DOWNLOADS WHEN USERS ARE ON A SLOW CONNECTION. โ† ADAPT TO SITUATIONS WHEN USERS ARE OFFLINE.
  161. NETWORK INFORMATION 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} />; }
  162. THIS SECTION PRESENTSโ€ฆ #1 ON THE WEB RESOURCE HINTS โ€ข

    PRIORITY HINTS โ€ข NATIVE LAZY- LOADING #2 IN REACT ALIASING REACT TO PREACT โ€ข WINDOWING โ€ข CODE SPLITTING โ€ข INFORMED CODE SPLITTING
  163. RESOURCE HINTS โ† MANY PERFORMANCE OPTIMIZATIONS CAN BE MADE WHEN

    WE CAN PREDICT WHAT USERS MIGHT DO. โ† RESOURCE HINTS ARE A SIMPLE BUT EFFECTIVE WAY TO ALLOW DEVELOPERS TO HELP THE BROWSER TO STAY ONE STEP AHEAD OF THE USER AND KEEP PAGES FAST.
  164. RESOURCE HINTS < ! - - Preconnect - - >

    <link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://scripts.example.com"> < ! - - Preloading - - > <link rel="preload" href="https://example.com/fonts/font.woff"> < ! - - DNS Prefetch - - > <link rel="dns-prefetch" href="https://fonts.gstatic.com"> <link rel="dns-prefetch" href="https://images.example.com"> < ! - - Prefetch - - > <link rel="prefetch" href="/uploads/images/pic.png"> <link rel="prefetch" href="https://example.com/news/?page=2"> < ! - - Prerender - - > <link rel="prerender" href="https://example.com/news/?page=2">
  165. RESOURCE HINTS < ! - - Preconnect - - >

    <link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://scripts.example.com"> < ! - - Preloading - - > <link rel="preload" href="https://example.com/fonts/font.woff"> < ! - - DNS Prefetch - - > <link rel="dns-prefetch" href="https://fonts.gstatic.com"> <link rel="dns-prefetch" href="https://images.example.com"> < ! - - Prefetch - - > <link rel="prefetch" href="/uploads/images/pic.png"> <link rel="prefetch" href="https://example.com/news/?page=2"> < ! - - Prerender - - > <link rel="prerender" href="https://example.com/news/?page=2">
  166. PRECONNECT โ† IT ALLOWS THE BROWSER TO SETUP EARLY CONNECTIONS

    BEFORE THE REQUEST IS ACTUALLY SENT TO THE SERVER. THIS INCLUDES: โ€ขTLS NEGOTIATIONS โ€ขTCP HANDSHAKES โ† ELIMINATES ROUNDTRIP LATENCY.
  167. PRECONNECT 100MS 200MS 300MS 400MS 500MS 600MS 700MS HTML CSS

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

    FONT 1 FONT 2 FONTS START LOADING FONTS RENDERED FONT 1 FONT 2
  169. โ€ฆAND MUCH MORE! โ† DNS PREFETCH: WARNS THE BROWSER ABOUT

    THE DOMAINS ITโ€™S GOING TO NEED TO LOOK UP. โ† PREFETCH: FETCH RESOURCES IN THE BACKGROUND AND STORE THEM IN CACHE. โ† PRERENDER: IT GOES ONE STEP FURTHER AND EXECUTES THE FILES.
  170. PRIORITY HINTS โ† INCREASE THE PRIORITY OF THE LCP IMAGE.

    โ† LOWER THE PRIORITY OF ABOVE-THE-FOLD IMAGES AND PRELOADED RESOURCES. โ† LOWER THE PRIORITY FOR NON-CRITICAL DATA FETCHES. โ† REPRIORITIZE SCRIPTS.
  171. PRIORITY HINTS < ! - - 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>
  172. PRIORITY HINTS < ! - - 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>
  173. PRIORITY HINTS / / Important validation data const user =

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

    await fetch("/user"); / / Less important content data const relatedPosts = await fetch("/posts/suggested", { priority: "low" });
  175. #research ๐Ÿ“š 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
  176. PREACT: OVERVIEW โ† WAY SMALLER BUNDLE (APPROXIMATELY 3.5KB). โ† FASTER

    VIRTUAL DOM IMPLEMENTATION. โ† MORE EFFECTIVE MEMORY USAGE.
  177. PREACT: CASE STUDY 205.9KB MIN + GZIP / NO POLYFILLS

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

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

    unsupported> <NetworkStatus networkInfo="unsupported" /> <Video /> </With> <With effectiveConnectionType="2g"> <NetworkStatus networkInfo="2g" /> <Preview /> </With> </Suspense>
  180. โ† RENDERING IN THE BACKGROUND WITH NO ADDITIONAL PERFORMANCE OVERHEAD.

    โ† IT DOESN'T MOUNT UNTIL THE COMPONENT BECOMES VISIBLE AND ITS EFFECTS ARE NOT FIRED. โ† TOGGLE THE VISIBILITY WITHOUT LOSING THE STATE. โ† INTEGRATED INTO ROUTERS AND OTHER UI LIBRARIES. OFFSCREEN ACTIVITY
  181. โ† ROUTERS CAN PRE-RENDER SCREENS IN THE BACKGROUND SO THAT

    THEYโ€™RE INSTANTLY AVAILABLE. โ† TAB SWITCHING CAN PRESERVE THE STATE OF HIDDEN TABS, SO THE USER CAN SWITCH BETWEEN THEM WITHOUT LOSING THEIR PROGRESS. โ† A VIRTUALIZED LIST CAN PRERENDER ADDITIONAL ROWS ABOVE AND BELOW THE VISIBLE WINDOW. OFFSCREEN ACTIVITY
  182. SUSPENSE FOR CPU-BOUND TREES โ† FORCES A FALLBACK ON THE

    INITIAL RENDER REGARDLESS OF WHETHER SOMETHING IS SUSPENDED. โ† DURING THE INITIAL MOUNT, REACT WILL SKIP OVER EXPENSIVE TREES BY RENDERING A PLACEHOLDER. โ† IT HELPS UNBLOCK THE INITIAL SKELETON FOR THE NEW SCREEN.
  183. โ† MODIFIES SOME JS SEMANTICS TO ALLOW EFFICIENT SOUND TYPING.

    โ† BRIDGES PREDICTABLE C PERFORMANCE WITH JS USABILITY VIA NATIVE AOT COMPILATION. โ† MIX AND MATCH BYTE-CODE AND NATIVE CODE BASED ON YOUR NEEDS. STATIC HERMES
  184. REACT STRICT DOM โ† OPPOSITE APPROACH TO react-native-web. โ† SMALL

    POLYFILLS RESPONSIBLE FOR TRANSLATING ITS APIS TO REACT-NATIVE AND REACT-DOM PRIMITIVES. โ† LESS OVERHEAD WHEN RUNNING IN BROWSERS. โ† POWERED BY STYLEX.
  185. CODE EXTRACTION import json from "./foo.json" with { type: "json"

    }; import ComponentA from "./A" with { type: "client" } import ComponentB from "./B" with { type: "both" }
  186. WHY SOMETHING IS THE FUTURE ROUTING MPAs vs. SPAs CODE

    EXTRACTION OKB JAVASCRIPT REACTIVITY HYDRATION COMPILERS
  187. Understanding these internals and their rationales helps us implement our

    own abstractions. REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS/ #1 of 7
  188. OUR OWN ABSTRACTIONSโ€ฆ โ† GENERATOR-BASED SCHEDULER โ† FIRST CLASS SUPPORT

    FOR PROMISES โ† JSCODESHIFT-BASED ARCHITECTURE UPGRADE โ† THE BABEL-BASED MIGRATION โ† CUSTOM METRICS
  189. React tries to address the lack of some JavaScript/Web Platform

    resources. REACT: INTERNALS AND ADVANCED PERFORMANCE PATTERNS/ #3 of 7
  190. Don't take fast networks, CPUs and RAM for granted. REACT:

    INTERNALS AND ADVANCED PERFORMANCE PATTERNS/ #6 of 7