Skip to content

Commit 663c4b7

Browse files
committed
Stop relying on hierarchical IDs in ReactDefaultPerf
1 parent 5d94d7d commit 663c4b7

File tree

4 files changed

+67
-23
lines changed

4 files changed

+67
-23
lines changed

src/renderers/dom/shared/ReactDOMComponent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,9 +1180,9 @@ ReactDOMComponent.Mixin = {
11801180

11811181
};
11821182

1183-
ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
1183+
ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', {
11841184
mountComponent: 'mountComponent',
1185-
updateComponent: 'updateComponent',
1185+
receiveComponent: 'receiveComponent',
11861186
});
11871187

11881188
assign(

src/renderers/dom/shared/ReactDOMTextComponent.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var DOMPropertyOperations = require('DOMPropertyOperations');
1818
var ReactComponentBrowserEnvironment =
1919
require('ReactComponentBrowserEnvironment');
2020
var ReactDOMComponentTree = require('ReactDOMComponentTree');
21+
var ReactPerf = require('ReactPerf');
2122

2223
var assign = require('Object.assign');
2324
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
@@ -153,4 +154,13 @@ assign(ReactDOMTextComponent.prototype, {
153154

154155
});
155156

157+
ReactPerf.measureMethods(
158+
ReactDOMTextComponent.prototype,
159+
'ReactDOMTextComponent',
160+
{
161+
mountComponent: 'mountComponent',
162+
receiveComponent: 'receiveComponent',
163+
}
164+
);
165+
156166
module.exports = ReactDOMTextComponent;

src/test/ReactDefaultPerf.js

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,26 @@ function addValue(obj, key, val) {
2828
obj[key] = (obj[key] || 0) + val;
2929
}
3030

31+
// Composites don't have any built-in ID: we have to make our own
32+
var compositeIDMap;
33+
var compositeIDCounter = 17000;
34+
function getIDOfComposite(inst) {
35+
if (!compositeIDMap) {
36+
compositeIDMap = new WeakMap();
37+
}
38+
if (compositeIDMap.has(inst)) {
39+
return compositeIDMap.get(inst);
40+
} else {
41+
var id = compositeIDCounter++;
42+
compositeIDMap.set(inst, id);
43+
return id;
44+
}
45+
}
46+
3147
var ReactDefaultPerf = {
3248
_allMeasurements: [], // last item in the list is the current one
3349
_mountStack: [0],
50+
_compositeStack: [],
3451
_injected: false,
3552

3653
start: function() {
@@ -125,10 +142,10 @@ var ReactDefaultPerf = {
125142

126143
_recordWrite: function(id, fnName, totalTime, args) {
127144
// TODO: totalTime isn't that useful since it doesn't count paints/reflows
128-
var writes =
145+
var entry =
129146
ReactDefaultPerf
130-
._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
131-
.writes;
147+
._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1];
148+
var writes = entry.writes;
132149
writes[id] = writes[id] || [];
133150
writes[id].push({
134151
type: fnName,
@@ -143,27 +160,30 @@ var ReactDefaultPerf = {
143160
var rv;
144161
var start;
145162

163+
var entry = ReactDefaultPerf._allMeasurements[
164+
ReactDefaultPerf._allMeasurements.length - 1
165+
];
166+
146167
if (fnName === '_renderNewRootComponent' ||
147168
fnName === 'flushBatchedUpdates') {
148169
// A "measurement" is a set of metrics recorded for each flush. We want
149170
// to group the metrics for a given flush together so we can look at the
150171
// components that rendered and the DOM operations that actually
151172
// happened to determine the amount of "wasted work" performed.
152-
ReactDefaultPerf._allMeasurements.push({
173+
ReactDefaultPerf._allMeasurements.push(entry = {
153174
exclusive: {},
154175
inclusive: {},
155176
render: {},
156177
counts: {},
157178
writes: {},
158179
displayNames: {},
180+
hierarchy: {},
159181
totalTime: 0,
160182
created: {},
161183
});
162184
start = performanceNow();
163185
rv = func.apply(this, args);
164-
ReactDefaultPerf._allMeasurements[
165-
ReactDefaultPerf._allMeasurements.length - 1
166-
].totalTime = performanceNow() - start;
186+
entry.totalTime = performanceNow() - start;
167187
return rv;
168188
} else if (fnName === '_mountImageIntoNode' ||
169189
moduleName === 'ReactDOMIDOperations' ||
@@ -228,16 +248,11 @@ var ReactDefaultPerf = {
228248
return func.apply(this, args);
229249
}
230250

231-
var rootNodeID = fnName === 'mountComponent' ?
232-
args[0] :
233-
this._rootNodeID;
251+
var rootNodeID = getIDOfComposite(this);
234252
var isRender = fnName === '_renderValidatedComponent';
235253
var isMount = fnName === 'mountComponent';
236254

237255
var mountStack = ReactDefaultPerf._mountStack;
238-
var entry = ReactDefaultPerf._allMeasurements[
239-
ReactDefaultPerf._allMeasurements.length - 1
240-
];
241256

242257
if (isRender) {
243258
addValue(entry.counts, rootNodeID, 1);
@@ -246,10 +261,14 @@ var ReactDefaultPerf = {
246261
mountStack.push(0);
247262
}
248263

264+
ReactDefaultPerf._compositeStack.push(rootNodeID);
265+
249266
start = performanceNow();
250267
rv = func.apply(this, args);
251268
totalTime = performanceNow() - start;
252269

270+
ReactDefaultPerf._compositeStack.pop();
271+
253272
if (isRender) {
254273
addValue(entry.render, rootNodeID, totalTime);
255274
} else if (isMount) {
@@ -269,6 +288,16 @@ var ReactDefaultPerf = {
269288
};
270289

271290
return rv;
291+
} else if (
292+
(moduleName === 'ReactDOMComponent' ||
293+
moduleName === 'ReactDOMTextComponent') &&
294+
(fnName === 'mountComponent' ||
295+
fnName === 'receiveComponent')) {
296+
297+
rv = func.apply(this, args);
298+
entry.hierarchy[this._rootNodeID] =
299+
ReactDefaultPerf._compositeStack.slice();
300+
return rv;
272301
} else {
273302
return func.apply(this, args);
274303
}

src/test/ReactDefaultPerfAnalysis.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,18 +173,23 @@ function getUnchangedComponents(measurement) {
173173
// render anything to the DOM and return a mapping of their ID to
174174
// the amount of time it took to render the entire subtree.
175175
var cleanComponents = {};
176-
var dirtyLeafIDs = Object.keys(measurement.writes);
176+
var writes = measurement.writes;
177+
var dirtyComposites = {};
178+
Object.keys(writes).forEach(function(id) {
179+
writes[id].forEach(function(write) {
180+
// Root mounting (innerHTML set) is recorded with an ID of ''
181+
if (id !== '') {
182+
measurement.hierarchy[id].forEach((c) => dirtyComposites[c] = true);
183+
}
184+
});
185+
});
177186
var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
178187

179188
for (var id in allIDs) {
180189
var isDirty = false;
181-
// For each component that rendered, see if a component that triggered
182-
// a DOM op is in its subtree.
183-
for (var i = 0; i < dirtyLeafIDs.length; i++) {
184-
if (dirtyLeafIDs[i].indexOf(id) === 0) {
185-
isDirty = true;
186-
break;
187-
}
190+
// See if any of the DOM operations applied to this component's subtree.
191+
if (dirtyComposites[id]) {
192+
isDirty = true;
188193
}
189194
// check if component newly created
190195
if (measurement.created[id]) {

0 commit comments

Comments
 (0)