Skip to content

Commit 1be3ce9

Browse files
authored
[Fiber] Bail out of diffing wide objects and arrays (facebook#34742)
1 parent 3b2a398 commit 1be3ce9

File tree

2 files changed

+395
-3
lines changed

2 files changed

+395
-3
lines changed
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @emails react-core
8+
* @jest-environment node
9+
*/
10+
11+
let React;
12+
let ReactNoop;
13+
let Scheduler;
14+
let act;
15+
let useEffect;
16+
17+
describe('ReactPerformanceTracks', () => {
18+
beforeEach(() => {
19+
Object.defineProperty(performance, 'measure', {
20+
value: jest.fn(),
21+
configurable: true,
22+
});
23+
console.timeStamp = () => {};
24+
jest.spyOn(console, 'timeStamp').mockImplementation(() => {});
25+
26+
jest.resetModules();
27+
28+
React = require('react');
29+
ReactNoop = require('react-noop-renderer');
30+
Scheduler = require('scheduler');
31+
act = require('internal-test-utils').act;
32+
useEffect = React.useEffect;
33+
});
34+
35+
// @gate __DEV__ && enableComponentPerformanceTrack
36+
it('shows a hint if an update is triggered by a deeply equal object', async () => {
37+
const App = function App({items}) {
38+
Scheduler.unstable_advanceTime(10);
39+
useEffect(() => {}, [items]);
40+
};
41+
42+
Scheduler.unstable_advanceTime(1);
43+
const items = ['one', 'two'];
44+
await act(() => {
45+
ReactNoop.render(<App items={items} />);
46+
});
47+
48+
expect(performance.measure.mock.calls).toEqual([
49+
[
50+
'Mount',
51+
{
52+
detail: {
53+
devtools: {
54+
color: 'warning',
55+
properties: null,
56+
tooltipText: 'Mount',
57+
track: 'Components ⚛',
58+
},
59+
},
60+
end: 11,
61+
start: 1,
62+
},
63+
],
64+
]);
65+
performance.measure.mockClear();
66+
67+
Scheduler.unstable_advanceTime(10);
68+
await act(() => {
69+
ReactNoop.render(<App items={items.concat('4')} />);
70+
});
71+
72+
expect(performance.measure.mock.calls).toEqual([
73+
[
74+
'​App',
75+
{
76+
detail: {
77+
devtools: {
78+
color: 'primary-dark',
79+
properties: [
80+
['Changed Props', ''],
81+
['  items', 'Array'],
82+
['+   2', '…'],
83+
],
84+
tooltipText: 'App',
85+
track: 'Components ⚛',
86+
},
87+
},
88+
end: 31,
89+
start: 21,
90+
},
91+
],
92+
]);
93+
});
94+
95+
// @gate __DEV__ && enableComponentPerformanceTrack
96+
it('bails out of diffing wide arrays', async () => {
97+
const App = function App({items}) {
98+
Scheduler.unstable_advanceTime(10);
99+
React.useEffect(() => {}, [items]);
100+
};
101+
102+
Scheduler.unstable_advanceTime(1);
103+
const items = Array.from({length: 1000}, (_, i) => i);
104+
await act(() => {
105+
ReactNoop.render(<App items={items} />);
106+
});
107+
108+
expect(performance.measure.mock.calls).toEqual([
109+
[
110+
'Mount',
111+
{
112+
detail: {
113+
devtools: {
114+
color: 'warning',
115+
properties: null,
116+
tooltipText: 'Mount',
117+
track: 'Components ⚛',
118+
},
119+
},
120+
end: 11,
121+
start: 1,
122+
},
123+
],
124+
]);
125+
performance.measure.mockClear();
126+
127+
Scheduler.unstable_advanceTime(10);
128+
await act(() => {
129+
ReactNoop.render(<App items={items.concat('-1')} />);
130+
});
131+
132+
expect(performance.measure.mock.calls).toEqual([
133+
[
134+
'​App',
135+
{
136+
detail: {
137+
devtools: {
138+
color: 'primary-dark',
139+
properties: [
140+
['Changed Props', ''],
141+
['  items', 'Array'],
142+
[
143+
'Previous object has more than 100 properties. React will not attempt to diff objects with too many properties.',
144+
'',
145+
],
146+
[
147+
'Next object has more than 100 properties. React will not attempt to diff objects with too many properties.',
148+
'',
149+
],
150+
],
151+
tooltipText: 'App',
152+
track: 'Components ⚛',
153+
},
154+
},
155+
end: 31,
156+
start: 21,
157+
},
158+
],
159+
]);
160+
});
161+
162+
// @gate __DEV__ && enableComponentPerformanceTrack
163+
it('does not show all properties of wide objects', async () => {
164+
const App = function App({items}) {
165+
Scheduler.unstable_advanceTime(10);
166+
React.useEffect(() => {}, [items]);
167+
};
168+
169+
Scheduler.unstable_advanceTime(1);
170+
await act(() => {
171+
ReactNoop.render(<App data={{buffer: null}} />);
172+
});
173+
174+
expect(performance.measure.mock.calls).toEqual([
175+
[
176+
'Mount',
177+
{
178+
detail: {
179+
devtools: {
180+
color: 'warning',
181+
properties: null,
182+
tooltipText: 'Mount',
183+
track: 'Components ⚛',
184+
},
185+
},
186+
end: 11,
187+
start: 1,
188+
},
189+
],
190+
]);
191+
performance.measure.mockClear();
192+
193+
Scheduler.unstable_advanceTime(10);
194+
195+
const bigData = new Uint8Array(1000);
196+
await act(() => {
197+
ReactNoop.render(<App data={{buffer: bigData}} />);
198+
});
199+
200+
expect(performance.measure.mock.calls).toEqual([
201+
[
202+
'​App',
203+
{
204+
detail: {
205+
devtools: {
206+
color: 'primary-dark',
207+
properties: [
208+
['Changed Props', ''],
209+
['  data', ''],
210+
['–   buffer', 'null'],
211+
['+   buffer', 'Uint8Array'],
212+
['+     0', '0'],
213+
['+     1', '0'],
214+
['+     2', '0'],
215+
['+     3', '0'],
216+
['+     4', '0'],
217+
['+     5', '0'],
218+
['+     6', '0'],
219+
['+     7', '0'],
220+
['+     8', '0'],
221+
['+     9', '0'],
222+
['+     10', '0'],
223+
['+     11', '0'],
224+
['+     12', '0'],
225+
['+     13', '0'],
226+
['+     14', '0'],
227+
['+     15', '0'],
228+
['+     16', '0'],
229+
['+     17', '0'],
230+
['+     18', '0'],
231+
['+     19', '0'],
232+
['+     20', '0'],
233+
['+     21', '0'],
234+
['+     22', '0'],
235+
['+     23', '0'],
236+
['+     24', '0'],
237+
['+     25', '0'],
238+
['+     26', '0'],
239+
['+     27', '0'],
240+
['+     28', '0'],
241+
['+     29', '0'],
242+
['+     30', '0'],
243+
['+     31', '0'],
244+
['+     32', '0'],
245+
['+     33', '0'],
246+
['+     34', '0'],
247+
['+     35', '0'],
248+
['+     36', '0'],
249+
['+     37', '0'],
250+
['+     38', '0'],
251+
['+     39', '0'],
252+
['+     40', '0'],
253+
['+     41', '0'],
254+
['+     42', '0'],
255+
['+     43', '0'],
256+
['+     44', '0'],
257+
['+     45', '0'],
258+
['+     46', '0'],
259+
['+     47', '0'],
260+
['+     48', '0'],
261+
['+     49', '0'],
262+
['+     50', '0'],
263+
['+     51', '0'],
264+
['+     52', '0'],
265+
['+     53', '0'],
266+
['+     54', '0'],
267+
['+     55', '0'],
268+
['+     56', '0'],
269+
['+     57', '0'],
270+
['+     58', '0'],
271+
['+     59', '0'],
272+
['+     60', '0'],
273+
['+     61', '0'],
274+
['+     62', '0'],
275+
['+     63', '0'],
276+
['+     64', '0'],
277+
['+     65', '0'],
278+
['+     66', '0'],
279+
['+     67', '0'],
280+
['+     68', '0'],
281+
['+     69', '0'],
282+
['+     70', '0'],
283+
['+     71', '0'],
284+
['+     72', '0'],
285+
['+     73', '0'],
286+
['+     74', '0'],
287+
['+     75', '0'],
288+
['+     76', '0'],
289+
['+     77', '0'],
290+
['+     78', '0'],
291+
['+     79', '0'],
292+
['+     80', '0'],
293+
['+     81', '0'],
294+
['+     82', '0'],
295+
['+     83', '0'],
296+
['+     84', '0'],
297+
['+     85', '0'],
298+
['+     86', '0'],
299+
['+     87', '0'],
300+
['+     88', '0'],
301+
['+     89', '0'],
302+
['+     90', '0'],
303+
['+     91', '0'],
304+
['+     92', '0'],
305+
['+     93', '0'],
306+
['+     94', '0'],
307+
['+     95', '0'],
308+
['+     96', '0'],
309+
['+     97', '0'],
310+
['+     98', '0'],
311+
['+     99', '0'],
312+
[
313+
'+     Only 100 properties are shown. React will not log more properties of this object.',
314+
'',
315+
],
316+
],
317+
tooltipText: 'App',
318+
track: 'Components ⚛',
319+
},
320+
},
321+
end: 31,
322+
start: 21,
323+
},
324+
],
325+
]);
326+
});
327+
});

0 commit comments

Comments
 (0)