@samitouri / QOS-React-2 / commits / a0f88d29df

Log top-level renders with console.time

Behind a flag.

Ben Alpert committed Nov 30, 2015 at 19:31 UTC a0f88d29df808137f0d95fde8d1ee5587540b4bb
5 files changed +121
src/renderers/dom/client/ReactMount.js
+17
@@ -19,6 +19,7 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree');
19 var ReactDOMContainerInfo = require('ReactDOMContainerInfo');
20 var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
21 var ReactElement = require('ReactElement');
22 +var ReactFeatureFlags = require('ReactFeatureFlags');
23 var ReactMarkupChecksum = require('ReactMarkupChecksum');
24 var ReactPerf = require('ReactPerf');
25 var ReactReconciler = require('ReactReconciler');
@@ -96,6 +97,17 @@ function mountComponentIntoNode(
97 shouldReuseMarkup,
98 context
99 ) {
100 + var markerName;
101 + if (ReactFeatureFlags.logTopLevelRenders) {
102 + var wrappedElement = wrapperInstance._currentElement.props;
103 + var type = wrappedElement.type;
104 + markerName = 'React mount: ' + (
105 + typeof type === 'string' ? type :
106 + type.displayName || type.name
107 + );
108 + console.time(markerName);
109 + }
110 +
111 var markup = ReactReconciler.mountComponent(
112 wrapperInstance,
113 transaction,
@@ -103,6 +115,11 @@ function mountComponentIntoNode(
115 ReactDOMContainerInfo(wrapperInstance, container),
116 context
117 );
118 +
119 + if (markerName) {
120 + console.timeEnd(markerName);
121 + }
122 +
123 wrapperInstance._renderedComponent._topLevelWrapper = wrapperInstance;
124 ReactMount._mountImageIntoNode(
125 markup,
src/renderers/dom/client/__tests__/ReactMount-test.js
+31
@@ -279,4 +279,35 @@ describe('ReactMount', function() {
279 ReactDOM.unmountComponentAtNode(container);
280 expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(1);
281 });
282 +
283 + it('marks top-level mounts', function() {
284 + var ReactFeatureFlags = require('ReactFeatureFlags');
285 +
286 + var Foo = React.createClass({
287 + render: function() {
288 + return <Bar />;
289 + },
290 + });
291 +
292 + var Bar = React.createClass({
293 + render: function() {
294 + return <div />;
295 + },
296 + });
297 +
298 + try {
299 + ReactFeatureFlags.logTopLevelRenders = true;
300 + spyOn(console, 'time');
301 + spyOn(console, 'timeEnd');
302 +
303 + ReactTestUtils.renderIntoDocument(<Foo />);
304 +
305 + expect(console.time.argsForCall.length).toBe(1);
306 + expect(console.time.argsForCall[0][0]).toBe('React mount: Foo');
307 + expect(console.timeEnd.argsForCall.length).toBe(1);
308 + expect(console.timeEnd.argsForCall[0][0]).toBe('React mount: Foo');
309 + } finally {
310 + ReactFeatureFlags.logTopLevelRenders = false;
311 + }
312 + });
313 });
src/renderers/shared/reconciler/ReactUpdates.js
+19
@@ -13,6 +13,7 @@
13
14 var CallbackQueue = require('CallbackQueue');
15 var PooledClass = require('PooledClass');
16 +var ReactFeatureFlags = require('ReactFeatureFlags');
17 var ReactPerf = require('ReactPerf');
18 var ReactReconciler = require('ReactReconciler');
19 var Transaction = require('Transaction');
@@ -149,11 +150,29 @@ function runBatchedUpdates(transaction) {
150 var callbacks = component._pendingCallbacks;
151 component._pendingCallbacks = null;
152
153 + var markerName;
154 + if (ReactFeatureFlags.logTopLevelRenders) {
155 + var namedComponent = component;
156 + // Duck type TopLevelWrapper. This is probably always true.
157 + if (
158 + component._currentElement.props ===
159 + component._renderedComponent._currentElement
160 + ) {
161 + namedComponent = component._renderedComponent;
162 + }
163 + markerName = 'React update: ' + namedComponent.getName();
164 + console.time(markerName);
165 + }
166 +
167 ReactReconciler.performUpdateIfNecessary(
168 component,
169 transaction.reconcileTransaction
170 );
171
172 + if (markerName) {
173 + console.timeEnd(markerName);
174 + }
175 +
176 if (callbacks) {
177 for (var j = 0; j < callbacks.length; j++) {
178 transaction.callbackQueue.enqueue(
src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js
+33
@@ -904,4 +904,37 @@ describe('ReactUpdates', function() {
904 expect(renderCount).toBe(1);
905 });
906
907 + it('marks top-level updates', function() {
908 + var ReactFeatureFlags = require('ReactFeatureFlags');
909 +
910 + var Foo = React.createClass({
911 + render: function() {
912 + return <Bar />;
913 + },
914 + });
915 +
916 + var Bar = React.createClass({
917 + render: function() {
918 + return <div />;
919 + },
920 + });
921 +
922 + var container = document.createElement('div');
923 + ReactDOM.render(<Foo />, container);
924 +
925 + try {
926 + ReactFeatureFlags.logTopLevelRenders = true;
927 + spyOn(console, 'time');
928 + spyOn(console, 'timeEnd');
929 +
930 + ReactDOM.render(<Foo />, container);
931 +
932 + expect(console.time.argsForCall.length).toBe(1);
933 + expect(console.time.argsForCall[0][0]).toBe('React update: Foo');
934 + expect(console.timeEnd.argsForCall.length).toBe(1);
935 + expect(console.timeEnd.argsForCall[0][0]).toBe('React update: Foo');
936 + } finally {
937 + ReactFeatureFlags.logTopLevelRenders = false;
938 + }
939 + });
940 });
src/shared/utils/ReactFeatureFlags.js new
+21
@@ -0,0 +1,21 @@
1 +/**
2 + * Copyright 2013-2015, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactFeatureFlags
10 + */
11 +
12 +'use strict';
13 +
14 +var ReactFeatureFlags = {
15 + // When true, call console.time() before and .timeEnd() after each top-level
16 + // render (both initial renders and updates). Useful when looking at prod-mode
17 + // timeline profiles in Chrome, for example.
18 + logTopLevelRenders: false,
19 +};
20 +
21 +module.exports = ReactFeatureFlags;