1+ import {
2+ onProfilerRender ,
3+ useBenchState ,
4+ waitForPaint ,
5+ } from '@shared/benchHarness' ;
16import { ItemRow } from '@shared/components' ;
27import {
3- FIXTURE_AUTHORS ,
8+ FIXTURE_AUTHORS_BY_ID ,
49 FIXTURE_ITEMS ,
510 generateFreshData ,
611} from '@shared/data' ;
7- import { captureSnapshot , getReport , registerRefs } from '@shared/refStability' ;
12+ import { registerRefs } from '@shared/refStability' ;
813import type { Item , UpdateAuthorOptions } from '@shared/types' ;
9- import React , {
10- useCallback ,
11- useContext ,
12- useEffect ,
13- useMemo ,
14- useRef ,
15- useState ,
16- } from 'react' ;
14+ import React , { useCallback , useContext , useMemo , useState } from 'react' ;
1715import { createRoot } from 'react-dom/client' ;
1816
1917const ItemsContext = React . createContext < {
@@ -46,134 +44,90 @@ function SortedListView() {
4644
4745function BenchmarkHarness ( ) {
4846 const [ items , setItems ] = useState < Item [ ] > ( [ ] ) ;
49- const [ ids , setIds ] = useState < string [ ] > ( [ ] ) ;
50- const [ showSortedView , setShowSortedView ] = useState ( false ) ;
51- const containerRef = useRef < HTMLDivElement > ( null ) ;
52- const completeResolveRef = useRef < ( ( ) => void ) | null > ( null ) ;
53-
54- const setComplete = useCallback ( ( ) => {
55- completeResolveRef . current ?.( ) ;
56- completeResolveRef . current = null ;
57- containerRef . current ?. setAttribute ( 'data-bench-complete' , 'true' ) ;
58- } , [ ] ) ;
47+ const {
48+ ids,
49+ showSortedView,
50+ containerRef,
51+ measureMount,
52+ measureUpdate,
53+ measureUpdateWithDelay,
54+ setComplete,
55+ completeResolveRef,
56+ setIds,
57+ setShowSortedView,
58+ unmountAll : unmountBase ,
59+ registerAPI,
60+ } = useBenchState ( ) ;
5961
6062 const mount = useCallback (
6163 ( n : number ) => {
62- performance . mark ( 'mount-start' ) ;
6364 const sliced = FIXTURE_ITEMS . slice ( 0 , n ) ;
64- setItems ( sliced ) ;
65- setIds ( sliced . map ( i => i . id ) ) ;
66- requestAnimationFrame ( ( ) => {
67- requestAnimationFrame ( ( ) => {
68- performance . mark ( 'mount-end' ) ;
69- performance . measure ( 'mount-duration' , 'mount-start' , 'mount-end' ) ;
70- setComplete ( ) ;
71- } ) ;
65+ const slicedIds = sliced . map ( i => i . id ) ;
66+ measureMount ( ( ) => {
67+ setItems ( sliced ) ;
68+ setIds ( slicedIds ) ;
7269 } ) ;
7370 } ,
74- [ setComplete ] ,
71+ [ measureMount , setIds ] ,
7572 ) ;
7673
7774 const updateEntity = useCallback (
7875 ( id : string ) => {
79- performance . mark ( 'update-start' ) ;
80- setItems ( prev =>
81- prev . map ( item =>
82- item . id === id ? { ...item , label : `${ item . label } (updated)` } : item ,
83- ) ,
84- ) ;
85- requestAnimationFrame ( ( ) => {
86- requestAnimationFrame ( ( ) => {
87- performance . mark ( 'update-end' ) ;
88- performance . measure ( 'update-duration' , 'update-start' , 'update-end' ) ;
89- setComplete ( ) ;
90- } ) ;
76+ measureUpdate ( ( ) => {
77+ setItems ( prev =>
78+ prev . map ( item =>
79+ item . id === id ?
80+ { ...item , label : `${ item . label } (updated)` }
81+ : item ,
82+ ) ,
83+ ) ;
9184 } ) ;
9285 } ,
93- [ setComplete ] ,
86+ [ measureUpdate ] ,
9487 ) ;
9588
9689 const updateAuthor = useCallback (
9790 ( authorId : string , options ?: UpdateAuthorOptions ) => {
98- performance . mark ( 'update-start' ) ;
99- const delayMs = options ?. simulateNetworkDelayMs ?? 0 ;
100- const requestCount = options ?. simulatedRequestCount ?? 1 ;
101- const totalDelayMs = delayMs * requestCount ;
102-
103- const doUpdate = ( ) => {
104- const author = FIXTURE_AUTHORS . find ( a => a . id === authorId ) ;
105- if ( author ) {
106- const newAuthor = {
107- ...author ,
108- name : `${ author . name } (updated)` ,
109- } ;
110- setItems ( prev =>
111- prev . map ( item =>
112- item . author . id === authorId ?
113- { ...item , author : newAuthor }
114- : item ,
115- ) ,
116- ) ;
117- }
118- requestAnimationFrame ( ( ) => {
119- requestAnimationFrame ( ( ) => {
120- performance . mark ( 'update-end' ) ;
121- performance . measure (
122- 'update-duration' ,
123- 'update-start' ,
124- 'update-end' ,
125- ) ;
126- setComplete ( ) ;
127- } ) ;
128- } ) ;
129- } ;
130-
131- if ( totalDelayMs > 0 ) {
132- setTimeout ( doUpdate , totalDelayMs ) ;
133- } else {
134- doUpdate ( ) ;
135- }
91+ const author = FIXTURE_AUTHORS_BY_ID . get ( authorId ) ;
92+ if ( ! author ) return ;
93+ const newAuthor = { ...author , name : `${ author . name } (updated)` } ;
94+ measureUpdateWithDelay ( options , ( ) => {
95+ setItems ( prev =>
96+ prev . map ( item =>
97+ item . author . id === authorId ? { ...item , author : newAuthor } : item ,
98+ ) ,
99+ ) ;
100+ } ) ;
136101 } ,
137- [ setComplete ] ,
102+ [ measureUpdateWithDelay ] ,
138103 ) ;
139104
140105 const unmountAll = useCallback ( ( ) => {
141- setIds ( [ ] ) ;
106+ unmountBase ( ) ;
142107 setItems ( [ ] ) ;
143- } , [ ] ) ;
108+ } , [ unmountBase ] ) ;
144109
145110 const bulkIngest = useCallback (
146111 ( n : number ) => {
147- performance . mark ( 'mount-start' ) ;
148112 const { items : freshItems } = generateFreshData ( n ) ;
149- setItems ( freshItems ) ;
150- setIds ( freshItems . map ( i => i . id ) ) ;
151- requestAnimationFrame ( ( ) => {
152- requestAnimationFrame ( ( ) => {
153- performance . mark ( 'mount-end' ) ;
154- performance . measure ( 'mount-duration' , 'mount-start' , 'mount-end' ) ;
155- setComplete ( ) ;
156- } ) ;
113+ const freshIds = freshItems . map ( i => i . id ) ;
114+ measureMount ( ( ) => {
115+ setItems ( freshItems ) ;
116+ setIds ( freshIds ) ;
157117 } ) ;
158118 } ,
159- [ setComplete ] ,
119+ [ measureMount , setIds ] ,
160120 ) ;
161121
162122 const mountSortedView = useCallback (
163123 ( n : number ) => {
164- performance . mark ( 'mount-start' ) ;
165124 const sliced = FIXTURE_ITEMS . slice ( 0 , n ) ;
166- setItems ( sliced ) ;
167- setShowSortedView ( true ) ;
168- requestAnimationFrame ( ( ) => {
169- requestAnimationFrame ( ( ) => {
170- performance . mark ( 'mount-end' ) ;
171- performance . measure ( 'mount-duration' , 'mount-start' , 'mount-end' ) ;
172- setComplete ( ) ;
173- } ) ;
125+ measureMount ( ( ) => {
126+ setItems ( sliced ) ;
127+ setShowSortedView ( true ) ;
174128 } ) ;
175129 } ,
176- [ setComplete ] ,
130+ [ measureMount , setShowSortedView ] ,
177131 ) ;
178132
179133 const mountUnmountCycle = useCallback (
@@ -185,55 +139,22 @@ function BenchmarkHarness() {
185139 mount ( n ) ;
186140 await p ;
187141 unmountAll ( ) ;
188- await new Promise < void > ( r =>
189- requestAnimationFrame ( ( ) => requestAnimationFrame ( ( ) => r ( ) ) ) ,
190- ) ;
142+ await waitForPaint ( ) ;
191143 }
192144 setComplete ( ) ;
193145 } ,
194- [ mount , unmountAll , setComplete ] ,
146+ [ mount , unmountAll , setComplete , completeResolveRef ] ,
195147 ) ;
196148
197- const getRenderedCount = useCallback ( ( ) => ids . length , [ ids ] ) ;
198-
199- const captureRefSnapshot = useCallback ( ( ) => {
200- captureSnapshot ( ) ;
201- } , [ ] ) ;
202-
203- const getRefStabilityReport = useCallback ( ( ) => getReport ( ) , [ ] ) ;
204-
205- useEffect ( ( ) => {
206- window . __BENCH__ = {
207- mount,
208- updateEntity,
209- updateAuthor,
210- unmountAll,
211- getRenderedCount,
212- captureRefSnapshot,
213- getRefStabilityReport,
214- mountUnmountCycle,
215- bulkIngest,
216- mountSortedView,
217- } ;
218- return ( ) => {
219- delete window . __BENCH__ ;
220- } ;
221- } , [
149+ registerAPI ( {
222150 mount,
223151 updateEntity,
224152 updateAuthor,
225153 unmountAll,
226154 mountUnmountCycle,
227155 bulkIngest,
228156 mountSortedView,
229- getRenderedCount ,
230- captureRefSnapshot ,
231- getRefStabilityReport ,
232- ] ) ;
233-
234- useEffect ( ( ) => {
235- document . body . setAttribute ( 'data-app-ready' , 'true' ) ;
236- } , [ ] ) ;
157+ } ) ;
237158
238159 return (
239160 < ItemsContext . Provider value = { { items, setItems } } >
@@ -249,17 +170,6 @@ function BenchmarkHarness() {
249170 ) ;
250171}
251172
252- function onProfilerRender (
253- _id : string ,
254- phase : 'mount' | 'update' | 'nested-update' ,
255- actualDuration : number ,
256- ) {
257- performance . measure ( `react-commit-${ phase } ` , {
258- start : performance . now ( ) - actualDuration ,
259- duration : actualDuration ,
260- } ) ;
261- }
262-
263173const rootEl = document . getElementById ( 'root' ) ?? document . body ;
264174createRoot ( rootEl ) . render (
265175 < React . Profiler id = "bench" onRender = { onProfilerRender } >
0 commit comments