[Perf Tracks] Don't enumerate typed array props in dev - #36913
Conversation
Passing a large TypedArray (e.g. `new Float32Array(25000000)`) as a prop froze rendering in development since 19.2. The performance track property logger recursed into the value and enumerated it with `for...in`, which forces the engine to materialize a key for every index up front (~2s+ for 25M elements) even though the loop breaks after 100 entries. Skip enumeration for typed arrays and show the type and length instead (e.g. `Float32Array(25000000)`), which is both fast and more useful. `ArrayBuffer` and `DataView` don't have enumerable indexed properties, so they were never affected. Fixes react#36200 Co-Authored-By: Baradhan-Madhu <26barum@gmail.com>
|
Comparing: 3508aee...05eae48 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
|
|
||
| Scheduler.unstable_advanceTime(10); | ||
|
|
||
| const bigData = new Uint8Array(1000); |
There was a problem hiding this comment.
Why change this? The assertions should be updated instead to show the new behavior.
| indent: number, | ||
| prefix: string, | ||
| ): void { | ||
| if (ArrayBuffer.isView(object) && typeof object.length === 'number') { |
There was a problem hiding this comment.
Why do we need the object.length check?
|
Can you check why we don't have a similar issue when sending Server Component props with Flight for debugging in React DevTools? |
|
Flight never has this problem because it type-checks typed arrays before any generic property enumeration and ships them as raw binary, so it never really walks their indices. |
DiffTrain build for [e71a639](react@e71a639)
DiffTrain build for [e71a639](react@e71a639)
Summary
Fixes #36200.
Passing a large
TypedArray(e.g.new Float32Array(25000000)) as a propfreezes rendering in development mode since 19.2 (production is unaffected).
The Performance Tracks property logger in
ReactPerformanceTrackProperties.jsrecurses into object prop values via
addObjectToProperties, which enumeratesthem with
for...in. For a typed array this forces the engine to materialize astring key for every index up front before the loop body runs, so the
existing
OBJECT_WIDTH_LIMITearly-break(at 100 entries) never helps. A25M-element array takes ~2s+ just to set up the enumeration, and the render
appears to hang.
Quick repro of the underlying cost:
This change skips enumeration for typed arrays and instead shows the type and
length (e.g.
Float32Array(25000000)), which is fast and more useful than atruncated list of numeric indices.
ArrayBufferandDataViewhave noenumerable indexed properties, so they were never affected and keep their
existing behavior.
The guard is added in two places:
addValueToProperties— the path used for component props (the reportedcase), producing the
Type(length)descriptor.addObjectToProperties— a defensive early return so the direct callers inFlight (e.g. resolved async values) also can't hit the slow enumeration.
How did you test this change?
shows the type and length of typed arrays instead of enumerating them) asserting the compactType(length)output.does not show all properties of wide objectstest touse a plain wide object so it keeps exercising the
OBJECT_WIDTH_LIMITtruncation (typed arrays no longer reach that path).
yarn test ReactPerformanceTrack— all pass.yarn flow dom-node— clean.