A Deep Dive Into Concurrent React by Matheus Albuquerque

ScyllaDB 98 views 64 slides Jun 27, 2024
Slide 1
Slide 1 of 85
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69
Slide 70
70
Slide 71
71
Slide 72
72
Slide 73
73
Slide 74
74
Slide 75
75
Slide 76
76
Slide 77
77
Slide 78
78
Slide 79
79
Slide 80
80
Slide 81
81
Slide 82
82
Slide 83
83
Slide 84
84
Slide 85
85

About This Presentation

Writing fluid user interfaces becomes more and more challenging as the application complexity increases. In this talk, we’ll explore how proper scheduling improves your app’s experience by diving into some of the concurrent React features, understanding their rationales, and how they work under ...


Slide Content

DEEP DIVING ON CONCURRENT REACT 👨💻 @medallia 🧑🏫 @techlabs 🐦 @ythecombinator ↑ ALL THE LINKS! 🤓 ⚡ Perf GDE

#DISCLAIMER 😌 This is a deep dive for those who are interested in API discussions . You don’t need to know all of that to be productive with React.

#QUESTION 🤔 If you were to summarize Concurrent React in one word/expression , what’d be your pick?

The Main Thread DEEP DIVING ON CONCURRENT REACT

#RESEARCH 📚 Phone users experience slow First Input Delay on 7x more websites. — Web Almanac By HTTP Archive, 2021

— AKAMAI AND CHROME RESEARCHµ 2017

#QUESTION 🤔 How to avoid blocking the main thread?

A B C D

PARALLELISM CONCURRENCY SCHEDULING

PARALLELISM CONCURRENCY SCHEDULING

↝ 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

🎭 ACTORS ↝ EACH ACTOR FULLY OWNS THE DATA IT IS OPERATING ON ↝ ACTORS CAN ONLY SEND/REACT TO MESSAGES ↝ THE MAIN THREAD IS ACTOR THAT OWNS THE DOM/UI ↝ postMessage HAS NO BUILT-IN UNDERSTANDING OF REQUEST AND RESPONSE ↝ BALANCE: MOVING CODE TO A WORKER VS COMMUNICATION OVERHEAD / WORKER BEING BUSY ↝ ONE DEDICATED TYPE: SharedArrayBuffer ↝ IF SENT VIA postMessage µ THE OTHER END GETS A HANDLE TO THE EXACT SAME MEMORY CHUNK ↝ MOST OF THE WEB APIS ARE BUILT NO CONCURRENT ACCESS TO OBJECTS ↝ YOU BUILD YOUR OWN CONCURRENT DATA STRUCTURES ↝ NO DIRECT WAY OF WORKING ON FAMILIAR OBJECTS/ARRAYS ; JUST A SERIES OF BYTES 🔗 SHARED MEMORY

🎭 ACTORS ↝ EACH ACTOR FULLY OWNS THE DATA IT IS OPERATING ON ↝ ACTORS CAN ONLY SEND/REACT TO MESSAGES ↝ THE MAIN THREAD IS ACTOR THAT OWNS THE DOM/UI ↝ postMessage HAS NO BUILT-IN UNDERSTANDING OF REQUEST AND RESPONSE ↝ BALANCE: MOVING CODE TO A WORKER VS COMMUNICATION OVERHEAD / WORKER BEING BUSY ↝ ONE DEDICATED TYPE: SharedArrayBuffer ↝ IF SENT VIA postMessage µ THE OTHER END GETS A HANDLE TO THE EXACT SAME MEMORY CHUNK ↝ MOST OF THE WEB APIS ARE BUILT NO CONCURRENT ACCESS TO OBJECTS ↝ YOU BUILD YOUR OWN CONCURRENT DATA STRUCTURES ↝ NO DIRECT WAY OF WORKING ON FAMILIAR OBJECTS/ARRAYS ; JUST A SERIES OF BYTES 🔗 SHARED MEMORY

↝ THE BEST EXPERIENCE FOR SHARED-MEMORY MODEL ↝ DOESN’T OFFER THE "COMFORT" OF JAVASCRIPT ↝ FASTER WHEN YOU STAY WITHIN WASM ↝ JAVASCRIPT IS OFTEN FASTER AT DOM AND HIGH- LEVEL UI LIBRARIES CAN BE MORE PERFORMANT THAN LOW-LEVEL WASM IMPLEMENTATIONS

↝ Atomics ↝ BuffferBackedObject ↝ Comlink ↝ WorkerDOM ↝ Partytown ↝ AND MUCH MORE !

↝ GOOD FOR DATA PROCESSING AND CRUNCHING NUMBERS ↝ HARD TO USE FOR UI-RELATED STUFF ↝ PERHAPS HARDER THAN ADJUSTING WORK FOR A SCHEDULER

PARALLELISM CONCURRENCY SCHEDULING

#QUESTION 🤔 If you were to summarize Concurrent React in one word/expression , what’d be your pick?

Scheduling in React DEEP DIVING ON CONCURRENT REACT

↝ 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

↓ ORIGINAL RENDER TASK USER INPUT → ↑ HIGHER PRIORITY RENDER TASK ↓ RESUME ORIGINAL RENDER TASK

↝ 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

#QUESTION 🤔 How do we benefit from these in our everyday projects ?

Scheduling in React [ for the rest of us ] DEEP DIVING ON CONCURRENT REACT

HANDLING LOTS OF DATA WITH THE useTransition HOOK TACKLING WASTED RENDERS WITH THE useSyncExternalStore HOOK HYDRATION IMPROVEMENTS WITH SELECTIVE HYDRATION & CONCURRENT REACT PROFILER ENHANCEMENTS INSPECT TRANSITIONS µ GET WARNS µ AND MUCH MORE!

#1 HANDLING LARGE SETS OF DATA DEEP DIVING ON CONCURRENT REACT

😔 NON-PRACTICAL… ↝ FINDING PRIMES ↝ CRACKING PASSWORDS ↝ SIERPINSKI TRIANGLE 😊 PRACTICAL… ↝ RENDERING MANY DATA-POINTS ↝ RENDERING ON A <canvas> ↝ PROCESSING DATA

😊 PRACTICAL… ↝ RENDERING MANY DATA-POINTS ↝ RENDERING ON A <canvas> ↝ PROCESSING DATA 😔 NON-PRACTICAL… ↝ FINDING PRIMES ↝ CRACKING PASSWORDS ↝ SIERPINSKI TRIANGLE

const DailyVisitors = () 3 { const [data, setData] = useState(initialData); useEffect(() 3 { setData(initialData); }, []); const onChange = (newData) 3 { setData(newData); }; return ( < Dashboard data ={ data } initialData ={ initialData } onChange ={ onChange } /> ); }; export default DailyVisitors;

const DailyVisitors = () 3 { const [data, setData] = useState(initialData); const [, startTransition] = useTransition(); useEffect(() 3 { setData(initialData); }, []); const onChange = (newData) 3 { startTransition(() 3 { setData(newData); }); }; return ( <Dashboard data={data} initialData={initialData} onChange={onChange} /> ); }; export default DailyVisitors;

↝ ˜ 100K + POINTS PLOTTED ↝ SUPPORT FOR SEARCHING AND FILTERING ↝ USED WORKERS + REDUX-SAGA UTILITIES + DEBOUNCING ↝ COULD'VE USED TRANSITIONS

↝ THOUSANDS OF REAL-TIME PLAYERS MESSAGING ↝ SUPPORT FOR SEARCHING AND FILTERING ↝ USED VIRTUALIZATION AND MEMOIZATION ↝ COULD'VE USED TRANSITIONS

#2 TACKLING WASTED RENDERS DEEP DIVING ON CONCURRENT REACT

3 () 3 void , function useSyncExternalStore< Snapshot >( subscribe: (onStoreChange: () 3 void ) getSnapshot: () 3 Snapshot, getServerSnapshot?: () 3 Snapshot ): Snapshot;

DEEP DIVING ON CONCURRENT REACT

#QUESTION 🤔 How do we benefit from these in our everyday projects ?

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

const { pathname } = useLocation(); const { hash } = useLocation(); OVER-RETURNING HOOK

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

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

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

#3 HYDRATION IMPROVEMENTS DEEP DIVING ON CONCURRENT REACT

FETCHING DATA (SERVER) RENDERING HTML (SERVER) LOADING CODE (CLIENT) HYDRATING TIME TO FIRST BYTE FIRST CONTENTFUL PAINT TIME TO INTERACTIVE

↝ HYDRATION COULD ONLY BEGIN AFTER THE ENTIRE DATA WAS FETCHED AND RENDERED ↝ USERS COULDN’T INTERACT WITH THE PAGE UNTIL HYDRATION WAS COMPLETE FOR THE WHOLE PAGE ↝ PARTS OF YOUR APP THAT LOAD FAST WOULD ALWAYS HAVE TO WAIT FOR THE SLOW ONES

DEEP DIVING ON CONCURRENT REACT

FETCHING DATA (SERVER) RENDERING HTML (SERVER) LOADING CODE (CLIENT) HYDRATING TIME TO FIRST BYTE FIRST CONTENTFUL PAINT TIME TO INTERACTIVE

TIME TO FIRST BYTE FIRST CONTENTFUL PAINT TIME TO INTERACTIVE […] FETCHING DATA (SERVER) RENDERING HTML (SERVER) HYDRATING LOADING CODE (CLIENT) […] […] […] […] […] […]

↝ pipeToNodeStream + createRoot + <Suspense> ↝ REACT PRIORITIZES HYDRATING THE PARTS THAT THE USER INTERACTED WITH BEFORE THE REST ↝ COMPONENTS CAN BECOME INTERACTIVE FASTER BY ALLOWING THE BROWSER TO DO OTHER WORK AT THE SAME TIME AS HYDRATION

↝ REACT WON'T WAIT FOR HUGE COMPONENTS TO LOAD TO CONTINUE STREAMING HTML FOR THE REST OF THE PAGE ↝ WHEN THE HTML BECOMES AVAILABLE ON THE SERVERµ IT WILL BE ADDED TO THE SAME STREAM ALONG WITH A SCRIPT TAG AND INSERTED IN THE RIGHT PLACE

DEEP DIVING ON CONCURRENT REACT

#4 PROFILER ENHANCEMENTS DEEP DIVING ON CONCURRENT REACT

— INTRODUCING A NEW REACT PROFILERµ BY BRIAN VAUGHN

— INTRODUCING A NEW REACT PROFILERµ BY BRIAN VAUGHN

The Future DEEP DIVING ON CONCURRENT REACT

↝ I/O LIBRARIES LIKE react-fetch ↝ BUILT-IN <Cache> FOR DATA FETCHING LIBRARIES TO INTEGRATE WITH <Suspense> ↝ <Suspense> FOR CPU-BOUND TREES TO IMMEDIATELY FALLBACK WITHOUT EVEN TRYING TO RENDER

↝ useInsertionEffect FOR STYLESHEET LIBRARIES ↝ THE <Offscreen> COMPONENT ↝ SERVER COMPONENTS ↝ NATIVE SCHEDULING PRIMITIVES ON THE BROWSER

DEEP DIVING ON CONCURRENT REACT

↝ A MORE ROBUST SOLUTION FOR SCHEDULING TASKS ↝ CONTROL AND SCHEDULE PRIORITIZED TASKS IN A UNITED AND FLEXIBLE WAY ↝ INTEGRATED DIRECTLY INTO THE EVENT LOOP ↝ ALIGNED WITH THE WORK OF THE REACT TEAM AND IN COOPERATION WITH GOOGLE µ W3C AND OTHERS

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.

Closing Notes DEEP DIVING ON CONCURRENT REACT

DEEP DIVING ON CONCURRENT REACT

#1 DEEP DIVING ON CONCURRENT REACT REACT IS NOT REACTIVEµ BUT IT IS CONCURRENT AND THAT MIGHT BE ENOUGH FOR YOU

#2 DEEP DIVING ON CONCURRENT REACT REACT HAS BEEN PUSHING WEB APIS TO THE FUTURE E.G. THE SCHEDULER API

#3 DEEP DIVING ON CONCURRENT REACT SCHEDULING DOES NOT NECESSARILY MEAN BETTER PERFORMANCE

#3 DEEP DIVING ON CONCURRENT REACT SCHEDULING DOES NOT NECESSARILY MEAN BETTER PERFORMANCE ↝ ↝ ↝ NON-URGENT UPDATES TAKE LONGER CAN’T HELP SOME EXPENSIVE COMPONENTS EXTRA CPU COST

#4 DEEP DIVING ON CONCURRENT REACT THERE'S NO SILVER BULLET . IDENTIFY YOUR CORE METRICS.

#5 DEEP DIVING ON CONCURRENT REACT THERE’S A LOT OF INFORMATION OUT THERE

#6 DEEP DIVING ON CONCURRENT REACT ALWAYS TRY TO CORRELATE BUSINESS METRICS WITH PERFORMANCE
Tags