[perf] New ReactDefaultPerf
Simplified version of https://github.com/facebook/react/pull/962. More goodies coming soon since the inclusive time isn't very helpful right now.
Pete Hunt committed
Feb 12, 2014 at 12:25 UTC
439bca78ed6482a068c29fe04f714a744c5cfbe2
2 files changed
+228
-435
src/browser/ReactComponentBrowserEnvironment.js
+64
-58
@@ -23,6 +23,7 @@
23
var ReactDOMIDOperations = require('ReactDOMIDOperations');
24
var ReactMarkupChecksum = require('ReactMarkupChecksum');
25
var ReactMount = require('ReactMount');
26
+var ReactPerf = require('ReactPerf');
27
var ReactReconcileTransaction = require('ReactReconcileTransaction');
28
29
var getReactRootElementInContainer = require('getReactRootElementInContainer');
@@ -79,71 +80,76 @@ var ReactComponentBrowserEnvironment = {
80
* @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
81
* container if possible.
82
*/
82
- mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
83
- invariant(
84
- container && (
85
- container.nodeType === ELEMENT_NODE_TYPE ||
86
- container.nodeType === DOC_NODE_TYPE
87
- ),
88
- 'mountComponentIntoNode(...): Target container is not valid.'
89
- );
90
-
91
- if (shouldReuseMarkup) {
92
- if (ReactMarkupChecksum.canReuseMarkup(
93
- markup,
94
- getReactRootElementInContainer(container))) {
95
- return;
96
- } else {
97
- invariant(
98
- container.nodeType !== DOC_NODE_TYPE,
99
- 'You\'re trying to render a component to the document using ' +
100
- 'server rendering but the checksum was invalid. This usually ' +
101
- 'means you rendered a different component type or props on ' +
102
- 'the client from the one on the server, or your render() methods ' +
103
- 'are impure. React cannot handle this case due to cross-browser ' +
104
- 'quirks by rendering at the document root. You should look for ' +
105
- 'environment dependent code in your components and ensure ' +
106
- 'the props are the same client and server side.'
107
- );
108
-
109
- if (__DEV__) {
110
- console.warn(
111
- 'React attempted to use reuse markup in a container but the ' +
112
- 'checksum was invalid. This generally means that you are using ' +
113
- 'server rendering and the markup generated on the server was ' +
114
- 'not what the client was expecting. React injected new markup ' +
115
- 'to compensate which works but you have lost many of the ' +
116
- 'benefits of server rendering. Instead, figure out why the ' +
117
- 'markup being generated is different on the client or server.'
83
+ mountImageIntoNode: ReactPerf.measure(
84
+ 'ReactComponentBrowserEnvironment',
85
+ 'mountImageIntoNode',
86
+ function(markup, container, shouldReuseMarkup) {
87
+ invariant(
88
+ container && (
89
+ container.nodeType === ELEMENT_NODE_TYPE ||
90
+ container.nodeType === DOC_NODE_TYPE
91
+ ),
92
+ 'mountComponentIntoNode(...): Target container is not valid.'
93
+ );
94
+
95
+ if (shouldReuseMarkup) {
96
+ if (ReactMarkupChecksum.canReuseMarkup(
97
+ markup,
98
+ getReactRootElementInContainer(container))) {
99
+ return;
100
+ } else {
101
+ invariant(
102
+ container.nodeType !== DOC_NODE_TYPE,
103
+ 'You\'re trying to render a component to the document using ' +
104
+ 'server rendering but the checksum was invalid. This usually ' +
105
+ 'means you rendered a different component type or props on ' +
106
+ 'the client from the one on the server, or your render() ' +
107
+ 'methods are impure. React cannot handle this case due to ' +
108
+ 'cross-browser quirks by rendering at the document root. You ' +
109
+ 'should look for environment dependent code in your components ' +
110
+ 'and ensure the props are the same client and server side.'
111
);
112
+
113
+ if (__DEV__) {
114
+ console.warn(
115
+ 'React attempted to use reuse markup in a container but the ' +
116
+ 'checksum was invalid. This generally means that you are ' +
117
+ 'using server rendering and the markup generated on the ' +
118
+ 'server was not what the client was expecting. React injected' +
119
+ 'new markup to compensate which works but you have lost many ' +
120
+ 'of the benefits of server rendering. Instead, figure out ' +
121
+ 'why the markup being generated is different on the client ' +
122
+ 'or server.'
123
+ );
124
+ }
125
}
126
}
121
- }
127
123
- invariant(
124
- container.nodeType !== DOC_NODE_TYPE,
125
- 'You\'re trying to render a component to the document but ' +
126
- 'you didn\'t use server rendering. We can\'t do this ' +
127
- 'without using server rendering due to cross-browser quirks. ' +
128
- 'See renderComponentToString() for server rendering.'
129
- );
130
-
131
- // Asynchronously inject markup by ensuring that the container is not in
132
- // the document when settings its `innerHTML`.
133
- var parent = container.parentNode;
134
- if (parent) {
135
- var next = container.nextSibling;
136
- parent.removeChild(container);
137
- container.innerHTML = markup;
138
- if (next) {
139
- parent.insertBefore(container, next);
128
+ invariant(
129
+ container.nodeType !== DOC_NODE_TYPE,
130
+ 'You\'re trying to render a component to the document but ' +
131
+ 'you didn\'t use server rendering. We can\'t do this ' +
132
+ 'without using server rendering due to cross-browser quirks. ' +
133
+ 'See renderComponentToString() for server rendering.'
134
+ );
135
+
136
+ // Asynchronously inject markup by ensuring that the container is not in
137
+ // the document when settings its `innerHTML`.
138
+ var parent = container.parentNode;
139
+ if (parent) {
140
+ var next = container.nextSibling;
141
+ parent.removeChild(container);
142
+ container.innerHTML = markup;
143
+ if (next) {
144
+ parent.insertBefore(container, next);
145
+ } else {
146
+ parent.appendChild(container);
147
+ }
148
} else {
141
- parent.appendChild(container);
149
+ container.innerHTML = markup;
150
}
143
- } else {
144
- container.innerHTML = markup;
151
}
146
- }
152
+ )
153
};
154
155
module.exports = ReactComponentBrowserEnvironment;
src/test/ReactDefaultPerf.js
+164
-377
@@ -17,406 +17,193 @@
17
* @typechecks static-only
18
*/
19
20
-"use strict";
21
-
20
+var ReactMount = require('ReactMount');
21
var ReactPerf = require('ReactPerf');
22
23
+var merge = require('merge');
24
var performanceNow = require('performanceNow');
25
26
-var ReactDefaultPerf = {};
27
-
28
-if (__DEV__) {
29
- ReactDefaultPerf = {
30
- _injected: false,
31
-
32
- start: function() {
33
- if (!ReactDefaultPerf._injected) {
34
- ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
35
- }
36
- ReactPerf.enableMeasure = true;
37
- },
38
-
39
- stop: function() {
40
- ReactPerf.enableMeasure = false;
41
- },
42
-
43
- /**
44
- * Gets the stored information for a given object's function.
45
- *
46
- * @param {string} objName
47
- * @param {string} fnName
48
- * @return {?object}
49
- */
50
- getInfo: function(objName, fnName) {
51
- if (!this.info[objName] || !this.info[objName][fnName]) {
52
- return null;
53
- }
54
- return this.info[objName][fnName];
55
- },
56
-
57
- /**
58
- * Gets the logs pertaining to a given object's function.
59
- *
60
- * @param {string} objName
61
- * @param {string} fnName
62
- * @return {?array<object>}
63
- */
64
- getLogs: function(objName, fnName) {
65
- if (!this.getInfo(objName, fnName)) {
66
- return null;
67
- }
68
- return this.logs.filter(function(log) {
69
- return log.objName === objName && log.fnName === fnName;
70
- });
71
- },
72
-
73
- /**
74
- * Runs through the logs and builds an array of arrays, where each array
75
- * walks through the mounting/updating of each component underneath.
76
- *
77
- * @param {string} rootID The reactID of the root node, e.g. '.0'
78
- * @return {array<array>}
79
- */
80
- getRawRenderHistory: function(rootID) {
81
- var history = [];
82
- /**
83
- * Since logs are added after the method returns, the logs are in a sense
84
- * upside-down: the inner-most elements from mounting/updating are logged
85
- * first, and the last addition to the log is the top renderComponent.
86
- * Therefore, we flip the logs upside down for ease of processing, and
87
- * reverse the history array at the end so the earliest event has index 0.
88
- */
89
- var logs = this.logs.filter(function(log) {
90
- return log.reactID.indexOf(rootID) === 0;
91
- }).reverse();
92
-
93
- var subHistory = [];
94
- logs.forEach(function(log, i) {
95
- if (i && log.reactID === rootID && logs[i - 1].reactID !== rootID) {
96
- subHistory.length && history.push(subHistory);
97
- subHistory = [];
98
- }
99
- subHistory.push(log);
100
- });
101
- if (subHistory.length) {
102
- history.push(subHistory);
103
- }
104
- return history.reverse();
105
- },
26
+// Don't try to save users less than 1.2ms (a number I made up)
27
+var DONT_CARE_THRESHOLD = 1.2;
28
107
- /**
108
- * Runs through the logs and builds an array of strings, where each string
109
- * is a multiline formatted way of walking through the mounting/updating
110
- * underneath.
111
- *
112
- * @param {string} rootID The reactID of the root node, e.g. '.0'
113
- * @return {array<string>}
114
- */
115
- getRenderHistory: function(rootID) {
116
- var history = this.getRawRenderHistory(rootID);
29
+function getSummary(measurements, sortInclusive) {
30
+ var candidates = {};
31
+ var totalDOMTime = 0;
32
+ var displayName;
33
118
- return history.map(function(subHistory) {
119
- var headerString = (
120
- 'log# Component (execution time) [bloat from logging]\n' +
121
- '================================================================\n'
122
- );
123
- return headerString + subHistory.map(function(log) {
124
- // Add two spaces for every layer in the reactID.
125
- var indents = '\t' + Array(log.reactID.split('.').length).join(' ');
126
- var delta = _microTime(log.timing.delta);
127
- var bloat = _microTime(log.timing.timeToLog);
34
+ for (var i = 0; i < measurements.length; i++) {
35
+ var measurement = measurements[i];
36
+ var id;
37
129
- return log.index + indents + log.name + ' (' + delta + 'ms)' +
130
- ' [' + bloat + 'ms]';
131
- }).join('\n');
38
+ for (id in measurement.writes) {
39
+ measurement.writes[id].forEach(function(write) {
40
+ totalDOMTime += write.time;
41
});
133
- },
134
-
135
- /**
136
- * Print the render history from `getRenderHistory` using console.log.
137
- * This is currently the best way to display perf data from
138
- * any React component; working on that.
139
- *
140
- * @param {string} rootID The reactID of the root node, e.g. '.0'
141
- * @param {number} index
142
- */
143
- printRenderHistory: function(rootID, index) {
144
- var history = this.getRenderHistory(rootID);
145
- if (!history[index]) {
146
- console.warn(
147
- 'Index', index, 'isn\'t available! ' +
148
- 'The render history is', history.length, 'long.'
149
- );
150
- return;
151
- }
152
- console.log(
153
- 'Loading render history #' + (index + 1) +
154
- ' of ' + history.length + ':\n' + history[index]
155
- );
156
- },
157
-
158
- /**
159
- * Prints the heatmap legend to console, showing how the colors correspond
160
- * with render times. This relies on console.log styles.
161
- */
162
- printHeatmapLegend: function() {
163
- if (!this.options.heatmap.enabled) {
164
- return;
165
- }
166
- var max = this.info.React
167
- && this.info.React.renderComponent
168
- && this.info.React.renderComponent.max;
169
- if (max) {
170
- var logStr = 'Heatmap: ';
171
- for (var ii = 0; ii <= 10 * max; ii += max) {
172
- logStr += '%c ' + (Math.round(ii) / 10) + 'ms ';
173
- }
174
- console.log(
175
- logStr,
176
- 'background-color: hsla(100, 100%, 50%, 0.6);',
177
- 'background-color: hsla( 90, 100%, 50%, 0.6);',
178
- 'background-color: hsla( 80, 100%, 50%, 0.6);',
179
- 'background-color: hsla( 70, 100%, 50%, 0.6);',
180
- 'background-color: hsla( 60, 100%, 50%, 0.6);',
181
- 'background-color: hsla( 50, 100%, 50%, 0.6);',
182
- 'background-color: hsla( 40, 100%, 50%, 0.6);',
183
- 'background-color: hsla( 30, 100%, 50%, 0.6);',
184
- 'background-color: hsla( 20, 100%, 50%, 0.6);',
185
- 'background-color: hsla( 10, 100%, 50%, 0.6);',
186
- 'background-color: hsla( 0, 100%, 50%, 0.6);'
187
- );
188
- }
189
- },
190
-
191
- /**
192
- * Measure a given function with logging information, and calls a callback
193
- * if there is one.
194
- *
195
- * @param {string} objName
196
- * @param {string} fnName
197
- * @param {function} func
198
- * @return {function}
199
- */
200
- measure: function(objName, fnName, func) {
201
- var info = _getNewInfo(objName, fnName);
202
-
203
- var fnArgs = _getFnArguments(func);
204
-
205
- return function(...args) {
206
- var timeBeforeFn = performanceNow();
207
- var fnReturn = func.apply(this, args);
208
- var timeAfterFn = performanceNow();
209
-
210
- /**
211
- * Hold onto arguments in a readable way: args[1] -> args.component.
212
- * args is also passed to the callback, so if you want to save an
213
- * argument in the log, do so in the callback.
214
- */
215
- var argsObject = {};
216
- for (var i = 0; i < args.length; i++) {
217
- argsObject[fnArgs[i]] = args[i];
218
- }
219
-
220
- var log = {
221
- index: ReactDefaultPerf.logs.length,
222
- fnName: fnName,
223
- objName: objName,
224
- timing: {
225
- before: timeBeforeFn,
226
- after: timeAfterFn,
227
- delta: timeAfterFn - timeBeforeFn
228
- }
229
- };
230
-
231
- ReactDefaultPerf.logs.push(log);
232
-
233
- /**
234
- * The callback gets:
235
- * - this (the component)
236
- * - the original method's arguments
237
- * - what the method returned
238
- * - the log object, and
239
- * - the wrapped method's info object.
240
- */
241
- var callback = _getCallback(objName, fnName);
242
- callback && callback(this, argsObject, fnReturn, log, info);
42
+ }
43
244
- log.timing.timeToLog = performanceNow() - timeAfterFn;
44
+ var allIDs = merge(measurement.exclusive, measurement.inclusive);
45
246
- return fnReturn;
46
+ for (id in allIDs) {
47
+ displayName = measurement.displayNames[id];
48
+ candidates[displayName] = candidates[displayName] || {
49
+ inclusive: 0,
50
+ exclusive: 0
51
};
248
- },
249
-
250
- /**
251
- * Holds information on wrapped objects/methods.
252
- * For instance, ReactDefaultPerf.info.React.renderComponent
253
- */
254
- info: {},
255
-
256
- /**
257
- * Holds all of the logs. Filter this to pull desired information.
258
- */
259
- logs: [],
260
-
261
- /**
262
- * Toggle settings for ReactDefaultPerf
263
- */
264
- options: {
265
- /**
266
- * The heatmap sets the background color of the React containers
267
- * according to how much total time has been spent rendering them.
268
- * The most temporally expensive component is set as pure red,
269
- * and the others are colored from green to red as a fraction
270
- * of that max component time.
271
- */
272
- heatmap: {
273
- enabled: true
52
+ if (measurement.exclusive[id]) {
53
+ candidates[displayName].exclusive += measurement.exclusive[id];
54
+ }
55
+ if (measurement.inclusive[id]) {
56
+ candidates[displayName].inclusive += measurement.inclusive[id];
57
}
58
}
276
- };
59
+ }
60
278
- /**
279
- * Gets a info area for a given object's function, adding a new one if
280
- * necessary.
281
- *
282
- * @param {string} objName
283
- * @param {string} fnName
284
- * @return {object}
285
- */
286
- var _getNewInfo = function(objName, fnName) {
287
- var info = ReactDefaultPerf.getInfo(objName, fnName);
288
- if (info) {
289
- return info;
61
+ // Now make a sorted array with the results.
62
+ var arr = [];
63
+ for (displayName in candidates) {
64
+ if (candidates[displayName] < DONT_CARE_THRESHOLD) {
65
+ continue;
66
}
291
- ReactDefaultPerf.info[objName] = ReactDefaultPerf.info[objName] || {};
292
-
293
- return ReactDefaultPerf.info[objName][fnName] = {
294
- getLogs: function() {
295
- return ReactDefaultPerf.getLogs(objName, fnName);
296
- }
297
- };
298
- };
67
+ arr.push({
68
+ componentName: displayName,
69
+ exclusiveTime: candidates[displayName].exclusive,
70
+ inclusiveTime: candidates[displayName].inclusive
71
+ });
72
+ }
73
+
74
+ if (sortInclusive) {
75
+ arr.sort(function(a, b) {
76
+ return b.inclusiveTime - a.inclusiveTime;
77
+ });
78
+ } else {
79
+ arr.sort(function(a, b) {
80
+ return b.exclusiveTime - a.exclusiveTime;
81
+ });
82
+ }
83
+
84
+ return {componentClasses: arr, totalDOMTime: totalDOMTime};
85
+}
86
300
- /**
301
- * Gets a list of the argument names from a function's definition.
302
- * This is useful for storing arguments by their names within wrapFn().
303
- *
304
- * @param {function} fn
305
- * @return {array<string>}
306
- */
307
- var _getFnArguments = function(fn) {
308
- var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
309
- var fnStr = fn.toString().replace(STRIP_COMMENTS, '');
310
- fnStr = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')'));
311
- return fnStr.match(/([^\s,]+)/g) || [];
312
- };
87
+var ReactDefaultPerf = {
88
+ _allMeasurements: null, // last item in the list is the current one
89
+ _injected: false,
90
314
- /**
315
- * Store common callbacks within ReactDefaultPerf.
316
- *
317
- * @param {string} objName
318
- * @param {string} fnName
319
- * @return {?function}
320
- */
321
- var _getCallback = function(objName, fnName) {
322
- switch (objName + '.' + fnName) {
323
- case 'React.renderComponent':
324
- return _renderComponentCallback;
325
- case 'ReactDOMComponent.mountComponent':
326
- case 'ReactDOMComponent.updateComponent':
327
- return _nativeComponentCallback;
328
- case 'ReactCompositeComponent.mountComponent':
329
- case 'ReactCompositeComponent.updateComponent':
330
- return _compositeComponentCallback;
331
- default:
332
- return null;
91
+ start: function() {
92
+ if (!ReactDefaultPerf._injected) {
93
+ ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
94
}
334
- };
335
-
336
- /**
337
- * Callback function for React.renderComponent
338
- *
339
- * @param {object} component
340
- * @param {object} args
341
- * @param {?object} fnReturn
342
- * @param {object} log
343
- * @param {object} info
344
- */
345
- var _renderComponentCallback =
346
- function(component, args, fnReturn, log, info) {
347
- log.name = args.nextComponent.constructor.displayName || '[unknown]';
348
- log.reactID = fnReturn._rootNodeID || null;
95
350
- if (ReactDefaultPerf.options.heatmap.enabled) {
351
- var container = args.container;
352
- if (!container.loggedByReactDefaultPerf) {
353
- container.loggedByReactDefaultPerf = true;
354
- info.components = info.components || [];
355
- info.components.push(container);
356
- }
357
-
358
- container.count = container.count || 0;
359
- container.count += log.timing.delta;
360
- info.max = info.max || 0;
361
- if (container.count > info.max) {
362
- info.max = container.count;
363
- info.components.forEach(function(component) {
364
- _setHue(component, 100 - 100 * component.count / info.max);
96
+ ReactDefaultPerf._allMeasurements = [];
97
+ ReactPerf.enableMeasure = true;
98
+ },
99
+
100
+ stop: function() {
101
+ ReactPerf.enableMeasure = false;
102
+ },
103
+
104
+ getLastMeasurements: function() {
105
+ return ReactDefaultPerf._allMeasurements;
106
+ },
107
+
108
+ printByExclusive: function(measurements) {
109
+ ReactDefaultPerf.print(measurements, false);
110
+ },
111
+
112
+ printByInclusive: function(measurements) {
113
+ ReactDefaultPerf.print(measurements, true);
114
+ },
115
+
116
+ print: function(measurements, sortInclusive) {
117
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
118
+ var summary = getSummary(measurements, sortInclusive);
119
+ console.table(summary.componentClasses.map(function(item) {
120
+ return {
121
+ 'Component class name': item.componentName,
122
+ 'Inclusive time': item.inclusiveTime.toFixed(2) + ' ms',
123
+ 'Exclusive time': item.exclusiveTime.toFixed(2) + ' ms'
124
+ };
125
+ }));
126
+ console.log('Total DOM time:', summary.totalDOMTime.toFixed(2) + ' ms');
127
+ },
128
+
129
+ _recordWrite: function(id, fnName, totalTime) {
130
+ var writes =
131
+ ReactDefaultPerf
132
+ ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
133
+ .writes;
134
+ writes[id] = writes[id] || [];
135
+ writes[id].push({
136
+ type: fnName,
137
+ time: totalTime
138
+ });
139
+ },
140
+
141
+ measure: function(moduleName, fnName, func) {
142
+ return function(...args) {
143
+ var totalTime;
144
+ var rv;
145
+ var start;
146
+
147
+ if (fnName === 'flushBatchedUpdates') {
148
+ // A "measurement" is a set of metrics recorded for each flush. We want
149
+ // to group the metrics for a given flush together so we can look at the
150
+ // components that rendered and the DOM operations that actually
151
+ // happened to determine the amount of "wasted work" performed.
152
+ ReactDefaultPerf._allMeasurements.push({
153
+ exclusive: {},
154
+ inclusive: {},
155
+ counts: {},
156
+ writes: {},
157
+ displayNames: {}
158
});
366
- } else {
367
- _setHue(container, 100 - 100 * container.count / info.max);
368
- }
369
- }
370
- };
371
-
372
- /**
373
- * Callback function for ReactDOMComponent
374
- *
375
- * @param {object} component
376
- * @param {object} args
377
- * @param {?object} fnReturn
378
- * @param {object} log
379
- * @param {object} info
380
- */
381
- var _nativeComponentCallback =
382
- function(component, args, fnReturn, log, info) {
383
- log.name = component.tagName || '[unknown]';
384
- log.reactID = component._rootNodeID;
385
- };
159
+ return func.apply(this, args);
160
+ } else if (moduleName === 'ReactDOMIDOperations' ||
161
+ moduleName === 'ReactComponentBrowserEnvironment') {
162
+ start = performanceNow();
163
+ rv = func.apply(this, args);
164
+ totalTime = performanceNow() - start;
165
+
166
+ if (fnName === 'mountImageIntoNode') {
167
+ var mountID = ReactMount.getID(args[1]);
168
+ ReactDefaultPerf._recordWrite(mountID, fnName, totalTime);
169
+ } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
170
+ // special format
171
+ args[0].forEach(function(update) {
172
+ ReactDefaultPerf._recordWrite(update.parentID, fnName, totalTime);
173
+ });
174
+ } else {
175
+ // basic format
176
+ ReactDefaultPerf._recordWrite(args[0], fnName, totalTime);
177
+ }
178
+ return rv;
179
+ } else if (fnName === 'updateComponent' ||
180
+ fnName === '_renderValidatedComponent') {
181
+ var isInclusive = fnName === 'updateComponent';
182
+ var entry = ReactDefaultPerf._allMeasurements[
183
+ ReactDefaultPerf._allMeasurements.length - 1
184
+ ];
185
+ if (isInclusive) {
186
+ // Since both updateComponent() and _renderValidatedComponent() are
187
+ // called for each render, only record the count for one of them.
188
+ entry.counts[this._rootNodeID] = entry.counts[this._rootNodeID] || 0;
189
+ entry.counts[this._rootNodeID] += 1;
190
+ }
191
+ start = performanceNow();
192
+ rv = func.apply(this, args);
193
+ totalTime = performanceNow() - start;
194
387
- /**
388
- * Callback function for ReactCompositeComponent
389
- *
390
- * @param {object} component
391
- * @param {object} args
392
- * @param {?object} fnReturn
393
- * @param {object} log
394
- * @param {object} info
395
- */
396
- var _compositeComponentCallback =
397
- function(component, args, fnReturn, log, info) {
398
- log.name = component.constructor.displayName || '[unknown]';
399
- log.reactID = component._rootNodeID;
400
- };
195
+ var typeOfLog = isInclusive ? entry.inclusive : entry.exclusive;
196
+ typeOfLog[this._rootNodeID] = typeOfLog[this._rootNodeID] || 0;
197
+ typeOfLog[this._rootNodeID] += totalTime;
198
402
- /**
403
- * Using the hsl() background-color attribute, colors an element.
404
- *
405
- * @param {DOMElement} el
406
- * @param {number} hue [0 for red, 120 for green, 240 for blue]
407
- */
408
- var _setHue = function(el, hue) {
409
- el.style.backgroundColor = 'hsla(' + hue + ', 100%, 50%, 0.6)';
410
- };
199
+ entry.displayNames[this._rootNodeID] = this.constructor.displayName;
200
412
- /**
413
- * Round to the thousandth place.
414
- * @param {number} time
415
- * @return {number}
416
- */
417
- var _microTime = function(time) {
418
- return Math.round(time * 1000) / 1000;
419
- };
201
+ return rv;
202
+ } else {
203
+ return func.apply(this, args);
204
+ }
205
+ };
206
+ }
207
}
208
209
module.exports = ReactDefaultPerf;