Stop relying on hierarchical IDs in ReactDefaultPerf
Ben Alpert committed
Oct 18, 2015 at 15:25 UTC
663c4b7d2ecbb93944da7e127401b782a663b470
4 files changed
+67
-23
src/renderers/dom/shared/ReactDOMComponent.js
+2
-2
@@ -1180,9 +1180,9 @@ ReactDOMComponent.Mixin = {
1180
1181
};
1182
1183
-ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
1183
+ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', {
1184
mountComponent: 'mountComponent',
1185
- updateComponent: 'updateComponent',
1185
+ receiveComponent: 'receiveComponent',
1186
});
1187
1188
assign(
src/renderers/dom/shared/ReactDOMTextComponent.js
+10
@@ -18,6 +18,7 @@ var DOMPropertyOperations = require('DOMPropertyOperations');
18
var ReactComponentBrowserEnvironment =
19
require('ReactComponentBrowserEnvironment');
20
var ReactDOMComponentTree = require('ReactDOMComponentTree');
21
+var ReactPerf = require('ReactPerf');
22
23
var assign = require('Object.assign');
24
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
@@ -153,4 +154,13 @@ assign(ReactDOMTextComponent.prototype, {
154
155
});
156
157
+ReactPerf.measureMethods(
158
+ ReactDOMTextComponent.prototype,
159
+ 'ReactDOMTextComponent',
160
+ {
161
+ mountComponent: 'mountComponent',
162
+ receiveComponent: 'receiveComponent',
163
+ }
164
+);
165
+
166
module.exports = ReactDOMTextComponent;
src/test/ReactDefaultPerf.js
+42
-13
@@ -28,9 +28,26 @@ function addValue(obj, key, val) {
28
obj[key] = (obj[key] || 0) + val;
29
}
30
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
+
47
var ReactDefaultPerf = {
48
_allMeasurements: [], // last item in the list is the current one
49
_mountStack: [0],
50
+ _compositeStack: [],
51
_injected: false,
52
53
start: function() {
@@ -125,10 +142,10 @@ var ReactDefaultPerf = {
142
143
_recordWrite: function(id, fnName, totalTime, args) {
144
// TODO: totalTime isn't that useful since it doesn't count paints/reflows
128
- var writes =
145
+ var entry =
146
ReactDefaultPerf
130
- ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
131
- .writes;
147
+ ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1];
148
+ var writes = entry.writes;
149
writes[id] = writes[id] || [];
150
writes[id].push({
151
type: fnName,
@@ -143,27 +160,30 @@ var ReactDefaultPerf = {
160
var rv;
161
var start;
162
163
+ var entry = ReactDefaultPerf._allMeasurements[
164
+ ReactDefaultPerf._allMeasurements.length - 1
165
+ ];
166
+
167
if (fnName === '_renderNewRootComponent' ||
168
fnName === 'flushBatchedUpdates') {
169
// A "measurement" is a set of metrics recorded for each flush. We want
170
// to group the metrics for a given flush together so we can look at the
171
// components that rendered and the DOM operations that actually
172
// happened to determine the amount of "wasted work" performed.
152
- ReactDefaultPerf._allMeasurements.push({
173
+ ReactDefaultPerf._allMeasurements.push(entry = {
174
exclusive: {},
175
inclusive: {},
176
render: {},
177
counts: {},
178
writes: {},
179
displayNames: {},
180
+ hierarchy: {},
181
totalTime: 0,
182
created: {},
183
});
184
start = performanceNow();
185
rv = func.apply(this, args);
164
- ReactDefaultPerf._allMeasurements[
165
- ReactDefaultPerf._allMeasurements.length - 1
166
- ].totalTime = performanceNow() - start;
186
+ entry.totalTime = performanceNow() - start;
187
return rv;
188
} else if (fnName === '_mountImageIntoNode' ||
189
moduleName === 'ReactDOMIDOperations' ||
@@ -228,16 +248,11 @@ var ReactDefaultPerf = {
248
return func.apply(this, args);
249
}
250
231
- var rootNodeID = fnName === 'mountComponent' ?
232
- args[0] :
233
- this._rootNodeID;
251
+ var rootNodeID = getIDOfComposite(this);
252
var isRender = fnName === '_renderValidatedComponent';
253
var isMount = fnName === 'mountComponent';
254
255
var mountStack = ReactDefaultPerf._mountStack;
238
- var entry = ReactDefaultPerf._allMeasurements[
239
- ReactDefaultPerf._allMeasurements.length - 1
240
- ];
256
257
if (isRender) {
258
addValue(entry.counts, rootNodeID, 1);
@@ -246,10 +261,14 @@ var ReactDefaultPerf = {
261
mountStack.push(0);
262
}
263
264
+ ReactDefaultPerf._compositeStack.push(rootNodeID);
265
+
266
start = performanceNow();
267
rv = func.apply(this, args);
268
totalTime = performanceNow() - start;
269
270
+ ReactDefaultPerf._compositeStack.pop();
271
+
272
if (isRender) {
273
addValue(entry.render, rootNodeID, totalTime);
274
} else if (isMount) {
@@ -269,6 +288,16 @@ var ReactDefaultPerf = {
288
};
289
290
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;
301
} else {
302
return func.apply(this, args);
303
}
src/test/ReactDefaultPerfAnalysis.js
+13
-8
@@ -173,18 +173,23 @@ function getUnchangedComponents(measurement) {
173
// render anything to the DOM and return a mapping of their ID to
174
// the amount of time it took to render the entire subtree.
175
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
+ });
186
var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
187
188
for (var id in allIDs) {
189
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;
193
}
194
// check if component newly created
195
if (measurement.created[id]) {