mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Delete the old ReactPerf
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactDefaultInjection = require('ReactDefaultInjection');
|
||||
var ReactMount = require('ReactMount');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var ReactVersion = require('ReactVersion');
|
||||
@@ -28,11 +27,9 @@ var warning = require('warning');
|
||||
|
||||
ReactDefaultInjection.inject();
|
||||
|
||||
var render = ReactPerf.measure('React', 'render', ReactMount.render);
|
||||
|
||||
var React = {
|
||||
findDOMNode: findDOMNode,
|
||||
render: render,
|
||||
render: ReactMount.render,
|
||||
unmountComponentAtNode: ReactMount.unmountComponentAtNode,
|
||||
version: ReactVersion,
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
var DOMChildrenOperations = require('DOMChildrenOperations');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
/**
|
||||
* Operations used to process updates to DOM nodes.
|
||||
@@ -32,8 +31,4 @@ var ReactDOMIDOperations = {
|
||||
},
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
|
||||
dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates',
|
||||
});
|
||||
|
||||
module.exports = ReactDOMIDOperations;
|
||||
|
||||
@@ -22,7 +22,6 @@ var ReactElement = require('ReactElement');
|
||||
var ReactFeatureFlags = require('ReactFeatureFlags');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactMarkupChecksum = require('ReactMarkupChecksum');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactUpdateQueue = require('ReactUpdateQueue');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
@@ -711,9 +710,4 @@ var ReactMount = {
|
||||
},
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(ReactMount, 'ReactMount', {
|
||||
_renderNewRootComponent: '_renderNewRootComponent',
|
||||
_mountImageIntoNode: '_mountImageIntoNode',
|
||||
});
|
||||
|
||||
module.exports = ReactMount;
|
||||
|
||||
@@ -16,7 +16,6 @@ var Danger = require('Danger');
|
||||
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
|
||||
var setInnerHTML = require('setInnerHTML');
|
||||
@@ -239,8 +238,4 @@ var DOMChildrenOperations = {
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', {
|
||||
replaceDelimitedText: 'replaceDelimitedText',
|
||||
});
|
||||
|
||||
module.exports = DOMChildrenOperations;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
var CSSProperty = require('CSSProperty');
|
||||
var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var camelizeStyleName = require('camelizeStyleName');
|
||||
var dangerousStyleValue = require('dangerousStyleValue');
|
||||
@@ -238,8 +237,4 @@ var CSSPropertyOperations = {
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', {
|
||||
setValueForStyles: 'setValueForStyles',
|
||||
});
|
||||
|
||||
module.exports = CSSPropertyOperations;
|
||||
|
||||
@@ -15,7 +15,6 @@ var DOMProperty = require('DOMProperty');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactDOMInstrumentation = require('ReactDOMInstrumentation');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
|
||||
var warning = require('warning');
|
||||
@@ -250,10 +249,4 @@ var DOMPropertyOperations = {
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', {
|
||||
setValueForProperty: 'setValueForProperty',
|
||||
setValueForAttribute: 'setValueForAttribute',
|
||||
deleteValueForProperty: 'deleteValueForProperty',
|
||||
});
|
||||
|
||||
module.exports = DOMPropertyOperations;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
var DOMChildrenOperations = require('DOMChildrenOperations');
|
||||
var ReactDOMIDOperations = require('ReactDOMIDOperations');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
/**
|
||||
* Abstracts away all functionality of the reconciler that requires knowledge of
|
||||
@@ -40,12 +39,4 @@ var ReactComponentBrowserEnvironment = {
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(
|
||||
ReactComponentBrowserEnvironment,
|
||||
'ReactComponentBrowserEnvironment',
|
||||
{
|
||||
replaceNodeWithMarkup: 'replaceNodeWithMarkup',
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = ReactComponentBrowserEnvironment;
|
||||
|
||||
@@ -34,7 +34,6 @@ var ReactDOMSelect = require('ReactDOMSelect');
|
||||
var ReactDOMTextarea = require('ReactDOMTextarea');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactMultiChild = require('ReactMultiChild');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
@@ -1129,11 +1128,6 @@ ReactDOMComponent.Mixin = {
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', {
|
||||
mountComponent: 'mountComponent',
|
||||
receiveComponent: 'receiveComponent',
|
||||
});
|
||||
|
||||
Object.assign(
|
||||
ReactDOMComponent.prototype,
|
||||
ReactDOMComponent.Mixin,
|
||||
|
||||
@@ -15,7 +15,6 @@ var DOMChildrenOperations = require('DOMChildrenOperations');
|
||||
var DOMLazyTree = require('DOMLazyTree');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
|
||||
var invariant = require('invariant');
|
||||
@@ -188,13 +187,4 @@ Object.assign(ReactDOMTextComponent.prototype, {
|
||||
|
||||
});
|
||||
|
||||
ReactPerf.measureMethods(
|
||||
ReactDOMTextComponent.prototype,
|
||||
'ReactDOMTextComponent',
|
||||
{
|
||||
mountComponent: 'mountComponent',
|
||||
receiveComponent: 'receiveComponent',
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = ReactDOMTextComponent;
|
||||
|
||||
@@ -15,7 +15,6 @@ var BeforeInputEventPlugin = require('BeforeInputEventPlugin');
|
||||
var ChangeEventPlugin = require('ChangeEventPlugin');
|
||||
var DefaultEventPluginOrder = require('DefaultEventPluginOrder');
|
||||
var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
|
||||
var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
|
||||
var ReactComponentBrowserEnvironment =
|
||||
require('ReactComponentBrowserEnvironment');
|
||||
@@ -91,14 +90,6 @@ function inject() {
|
||||
);
|
||||
|
||||
ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
|
||||
|
||||
if (__DEV__) {
|
||||
var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
|
||||
if ((/[?&]react_perf\b/).test(url)) {
|
||||
var ReactDefaultPerf = require('ReactDefaultPerf');
|
||||
ReactDefaultPerf.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -19,7 +19,6 @@ var ReactClass = require('ReactClass');
|
||||
var ReactEmptyComponent = require('ReactEmptyComponent');
|
||||
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
var ReactNativeComponent = require('ReactNativeComponent');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
|
||||
var ReactInjection = {
|
||||
@@ -31,7 +30,6 @@ var ReactInjection = {
|
||||
EventPluginUtils: EventPluginUtils.injection,
|
||||
EventEmitter: ReactBrowserEventEmitter.injection,
|
||||
NativeComponent: ReactNativeComponent.injection,
|
||||
Perf: ReactPerf.injection,
|
||||
Updates: ReactUpdates.injection,
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var UIManager = require('UIManager');
|
||||
|
||||
/**
|
||||
@@ -71,12 +70,7 @@ var dangerouslyProcessChildrenUpdates = function(inst, childrenUpdates) {
|
||||
* `ReactComponent.DOMIDOperations`.
|
||||
*/
|
||||
var ReactNativeDOMIDOperations = {
|
||||
dangerouslyProcessChildrenUpdates: ReactPerf.measure(
|
||||
// FIXME(frantic): #4441289 Hack to avoid modifying react-tools
|
||||
'ReactDOMIDOperations',
|
||||
'dangerouslyProcessChildrenUpdates',
|
||||
dangerouslyProcessChildrenUpdates
|
||||
),
|
||||
dangerouslyProcessChildrenUpdates,
|
||||
|
||||
/**
|
||||
* Replaces a view that exists in the document with markup.
|
||||
@@ -84,14 +78,10 @@ var ReactNativeDOMIDOperations = {
|
||||
* @param {string} id ID of child to be replaced.
|
||||
* @param {string} markup Mount image to replace child with id.
|
||||
*/
|
||||
dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
|
||||
'ReactDOMIDOperations',
|
||||
'dangerouslyReplaceNodeWithMarkupByID',
|
||||
function(id, mountImage) {
|
||||
var oldTag = id;
|
||||
UIManager.replaceExistingNonRootView(oldTag, mountImage);
|
||||
}
|
||||
),
|
||||
dangerouslyReplaceNodeWithMarkupByID: function(id, mountImage) {
|
||||
var oldTag = id;
|
||||
UIManager.replaceExistingNonRootView(oldTag, mountImage);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactNativeDOMIDOperations;
|
||||
|
||||
@@ -15,7 +15,6 @@ var ReactElement = require('ReactElement');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactUpdateQueue = require('ReactUpdateQueue');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
@@ -171,20 +170,15 @@ var ReactNativeMount = {
|
||||
* @param {View} view View tree image.
|
||||
* @param {number} containerViewID View to insert sub-view into.
|
||||
*/
|
||||
_mountImageIntoNode: ReactPerf.measure(
|
||||
// FIXME(frantic): #4441289 Hack to avoid modifying react-tools
|
||||
'ReactComponentBrowserEnvironment',
|
||||
'mountImageIntoNode',
|
||||
function(mountImage, containerID) {
|
||||
// Since we now know that the `mountImage` has been mounted, we can
|
||||
// mark it as such.
|
||||
var childTag = mountImage;
|
||||
UIManager.setChildren(
|
||||
containerID,
|
||||
[childTag]
|
||||
);
|
||||
}
|
||||
),
|
||||
_mountImageIntoNode: function(mountImage, containerID) {
|
||||
// Since we now know that the `mountImage` has been mounted, we can
|
||||
// mark it as such.
|
||||
var childTag = mountImage;
|
||||
UIManager.setChildren(
|
||||
containerID,
|
||||
[childTag]
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Standard unmounting of the component that is rendered into `containerID`,
|
||||
@@ -242,10 +236,4 @@ var ReactNativeMount = {
|
||||
|
||||
};
|
||||
|
||||
ReactNativeMount.renderComponent = ReactPerf.measure(
|
||||
'ReactMount',
|
||||
'_renderNewRootComponent',
|
||||
ReactNativeMount.renderComponent
|
||||
);
|
||||
|
||||
module.exports = ReactNativeMount;
|
||||
|
||||
@@ -18,7 +18,6 @@ var ReactErrorUtils = require('ReactErrorUtils');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactNodeTypes = require('ReactNodeTypes');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactPropTypeLocations = require('ReactPropTypeLocations');
|
||||
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
@@ -1210,16 +1209,6 @@ var ReactCompositeComponentMixin = {
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(
|
||||
ReactCompositeComponentMixin,
|
||||
'ReactCompositeComponent',
|
||||
{
|
||||
mountComponent: 'mountComponent',
|
||||
updateComponent: 'updateComponent',
|
||||
_renderValidatedComponent: '_renderValidatedComponent',
|
||||
}
|
||||
);
|
||||
|
||||
var ReactCompositeComponent = {
|
||||
|
||||
Mixin: ReactCompositeComponentMixin,
|
||||
|
||||
@@ -15,7 +15,6 @@ var CallbackQueue = require('CallbackQueue');
|
||||
var PooledClass = require('PooledClass');
|
||||
var ReactFeatureFlags = require('ReactFeatureFlags');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var Transaction = require('Transaction');
|
||||
|
||||
@@ -222,11 +221,6 @@ var flushBatchedUpdates = function() {
|
||||
ReactInstrumentation.debugTool.onEndFlush();
|
||||
}
|
||||
};
|
||||
flushBatchedUpdates = ReactPerf.measure(
|
||||
'ReactUpdates',
|
||||
'flushBatchedUpdates',
|
||||
flushBatchedUpdates
|
||||
);
|
||||
|
||||
/**
|
||||
* Mark a component as needing a rerender, adding an optional callback to a
|
||||
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactDefaultPerf
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var DOMProperty = require('DOMProperty');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
|
||||
var ReactMount = require('ReactMount');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var performanceNow = require('performanceNow');
|
||||
var warning = require('warning');
|
||||
|
||||
function roundFloat(val) {
|
||||
return Math.floor(val * 100) / 100;
|
||||
}
|
||||
|
||||
function addValue(obj, key, val) {
|
||||
obj[key] = (obj[key] || 0) + val;
|
||||
}
|
||||
|
||||
// Composite/text components don't have any built-in ID: we have to make our own
|
||||
var compositeIDMap;
|
||||
var compositeIDCounter = 17000;
|
||||
function getIDOfComposite(inst) {
|
||||
if (!compositeIDMap) {
|
||||
compositeIDMap = new WeakMap();
|
||||
}
|
||||
if (compositeIDMap.has(inst)) {
|
||||
return compositeIDMap.get(inst);
|
||||
} else {
|
||||
var id = compositeIDCounter++;
|
||||
compositeIDMap.set(inst, id);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
function getID(inst) {
|
||||
if (inst.hasOwnProperty('_rootNodeID')) {
|
||||
return inst._rootNodeID;
|
||||
} else {
|
||||
return getIDOfComposite(inst);
|
||||
}
|
||||
}
|
||||
|
||||
function stripComplexValues(key, value) {
|
||||
if (typeof value !== 'object' || Array.isArray(value) || value == null) {
|
||||
return value;
|
||||
}
|
||||
var prototype = Object.getPrototypeOf(value);
|
||||
if (!prototype || prototype === Object.prototype) {
|
||||
return value;
|
||||
}
|
||||
return '<not serializable>';
|
||||
}
|
||||
|
||||
// This implementation of ReactPerf is going away some time mid 15.x.
|
||||
// While we plan to keep most of the API, the actual format of measurements
|
||||
// will change dramatically. To signal this, we wrap them into an opaque-ish
|
||||
// object to discourage reaching into it until the API stabilizes.
|
||||
function wrapLegacyMeasurements(measurements) {
|
||||
return { __unstable_this_format_will_change: measurements };
|
||||
}
|
||||
function unwrapLegacyMeasurements(measurements) {
|
||||
return measurements && measurements.__unstable_this_format_will_change || measurements;
|
||||
}
|
||||
|
||||
var warnedAboutPrintDOM = false;
|
||||
var warnedAboutGetMeasurementsSummaryMap = false;
|
||||
|
||||
var ReactDefaultPerf = {
|
||||
_allMeasurements: [], // last item in the list is the current one
|
||||
_mountStack: [0],
|
||||
_compositeStack: [],
|
||||
_injected: false,
|
||||
|
||||
start: function() {
|
||||
if (!ReactDefaultPerf._injected) {
|
||||
ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
|
||||
}
|
||||
|
||||
ReactDefaultPerf._allMeasurements.length = 0;
|
||||
ReactPerf.enableMeasure = true;
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
ReactPerf.enableMeasure = false;
|
||||
},
|
||||
|
||||
getLastMeasurements: function() {
|
||||
return wrapLegacyMeasurements(ReactDefaultPerf._allMeasurements);
|
||||
},
|
||||
|
||||
printExclusive: function(measurements) {
|
||||
measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
|
||||
var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
|
||||
console.table(summary.map(function(item) {
|
||||
return {
|
||||
'Component class name': item.componentName,
|
||||
'Total inclusive time (ms)': roundFloat(item.inclusive),
|
||||
'Exclusive mount time (ms)': roundFloat(item.exclusive),
|
||||
'Exclusive render time (ms)': roundFloat(item.render),
|
||||
'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
|
||||
'Render time per instance (ms)': roundFloat(item.render / item.count),
|
||||
'Instances': item.count,
|
||||
};
|
||||
}));
|
||||
// TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
|
||||
// number.
|
||||
},
|
||||
|
||||
printInclusive: function(measurements) {
|
||||
measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
|
||||
var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
|
||||
console.table(summary.map(function(item) {
|
||||
return {
|
||||
'Owner > component': item.componentName,
|
||||
'Inclusive time (ms)': roundFloat(item.time),
|
||||
'Instances': item.count,
|
||||
};
|
||||
}));
|
||||
console.log(
|
||||
'Total time:',
|
||||
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
|
||||
);
|
||||
},
|
||||
|
||||
getMeasurementsSummaryMap: function(measurements) {
|
||||
warning(
|
||||
warnedAboutGetMeasurementsSummaryMap,
|
||||
'`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
|
||||
'`ReactPerf.getWasted(...)` instead.'
|
||||
);
|
||||
warnedAboutGetMeasurementsSummaryMap = true;
|
||||
return ReactDefaultPerf.getWasted(measurements);
|
||||
},
|
||||
|
||||
getWasted: function(measurements) {
|
||||
measurements = unwrapLegacyMeasurements(measurements);
|
||||
var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
|
||||
measurements,
|
||||
true
|
||||
);
|
||||
return summary.map(function(item) {
|
||||
return {
|
||||
'Owner > component': item.componentName,
|
||||
'Wasted time (ms)': item.time,
|
||||
'Instances': item.count,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
printWasted: function(measurements) {
|
||||
measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
|
||||
console.table(ReactDefaultPerf.getWasted(measurements));
|
||||
console.log(
|
||||
'Total time:',
|
||||
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
|
||||
);
|
||||
},
|
||||
|
||||
printDOM: function(measurements) {
|
||||
warning(
|
||||
warnedAboutPrintDOM,
|
||||
'`ReactPerf.printDOM(...)` is deprecated. Use ' +
|
||||
'`ReactPerf.printOperations(...)` instead.'
|
||||
);
|
||||
warnedAboutPrintDOM = true;
|
||||
return ReactDefaultPerf.printOperations(measurements);
|
||||
},
|
||||
|
||||
printOperations: function(measurements) {
|
||||
measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
|
||||
var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
|
||||
console.table(summary.map(function(item) {
|
||||
var result = {};
|
||||
result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
|
||||
result.type = item.type;
|
||||
result.args = JSON.stringify(item.args, stripComplexValues);
|
||||
return result;
|
||||
}));
|
||||
console.log(
|
||||
'Total time:',
|
||||
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
|
||||
);
|
||||
},
|
||||
|
||||
_recordWrite: function(id, fnName, totalTime, args) {
|
||||
// TODO: totalTime isn't that useful since it doesn't count paints/reflows
|
||||
var entry =
|
||||
ReactDefaultPerf
|
||||
._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1];
|
||||
var writes = entry.writes;
|
||||
writes[id] = writes[id] || [];
|
||||
writes[id].push({
|
||||
type: fnName,
|
||||
time: totalTime,
|
||||
args: args,
|
||||
});
|
||||
},
|
||||
|
||||
measure: function(moduleName, fnName, func) {
|
||||
return function(...args) {
|
||||
var totalTime;
|
||||
var rv;
|
||||
var start;
|
||||
|
||||
var entry = ReactDefaultPerf._allMeasurements[
|
||||
ReactDefaultPerf._allMeasurements.length - 1
|
||||
];
|
||||
|
||||
if (fnName === '_renderNewRootComponent' ||
|
||||
fnName === 'flushBatchedUpdates') {
|
||||
// A "measurement" is a set of metrics recorded for each flush. We want
|
||||
// to group the metrics for a given flush together so we can look at the
|
||||
// components that rendered and the DOM operations that actually
|
||||
// happened to determine the amount of "wasted work" performed.
|
||||
ReactDefaultPerf._allMeasurements.push(entry = {
|
||||
exclusive: {},
|
||||
inclusive: {},
|
||||
render: {},
|
||||
counts: {},
|
||||
writes: {},
|
||||
displayNames: {},
|
||||
hierarchy: {},
|
||||
totalTime: 0,
|
||||
created: {},
|
||||
});
|
||||
start = performanceNow();
|
||||
rv = func.apply(this, args);
|
||||
entry.totalTime = performanceNow() - start;
|
||||
return rv;
|
||||
} else if (fnName === '_mountImageIntoNode' ||
|
||||
moduleName === 'ReactDOMIDOperations' ||
|
||||
moduleName === 'CSSPropertyOperations' ||
|
||||
moduleName === 'DOMChildrenOperations' ||
|
||||
moduleName === 'DOMPropertyOperations' ||
|
||||
moduleName === 'ReactComponentBrowserEnvironment') {
|
||||
start = performanceNow();
|
||||
rv = func.apply(this, args);
|
||||
totalTime = performanceNow() - start;
|
||||
|
||||
if (fnName === '_mountImageIntoNode') {
|
||||
ReactDefaultPerf._recordWrite('', fnName, totalTime, args[0]);
|
||||
} else if (fnName === 'dangerouslyProcessChildrenUpdates') {
|
||||
// special format
|
||||
args[1].forEach(function(update) {
|
||||
var writeArgs = {};
|
||||
if (update.fromIndex !== null) {
|
||||
writeArgs.fromIndex = update.fromIndex;
|
||||
}
|
||||
if (update.toIndex !== null) {
|
||||
writeArgs.toIndex = update.toIndex;
|
||||
}
|
||||
if (update.content !== null) {
|
||||
writeArgs.content = update.content;
|
||||
}
|
||||
ReactDefaultPerf._recordWrite(
|
||||
args[0]._rootNodeID,
|
||||
update.type,
|
||||
totalTime,
|
||||
writeArgs
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// basic format
|
||||
var id = args[0];
|
||||
if (moduleName === 'EventPluginHub') {
|
||||
id = id._rootNodeID;
|
||||
} else if (fnName === 'replaceNodeWithMarkup') {
|
||||
// Old node is already unmounted; can't get its instance
|
||||
id = ReactDOMComponentTree.getInstanceFromNode(args[1].node)._rootNodeID;
|
||||
} else if (fnName === 'replaceDelimitedText') {
|
||||
id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0]));
|
||||
} else if (typeof id === 'object') {
|
||||
id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0]));
|
||||
}
|
||||
ReactDefaultPerf._recordWrite(
|
||||
id,
|
||||
fnName,
|
||||
totalTime,
|
||||
Array.prototype.slice.call(args, 1)
|
||||
);
|
||||
}
|
||||
return rv;
|
||||
} else if (moduleName === 'ReactCompositeComponent' && (
|
||||
fnName === 'mountComponent' ||
|
||||
fnName === 'updateComponent' || // TODO: receiveComponent()?
|
||||
fnName === '_renderValidatedComponent')) {
|
||||
|
||||
if (this._currentElement.type === ReactMount.TopLevelWrapper) {
|
||||
return func.apply(this, args);
|
||||
}
|
||||
|
||||
var rootNodeID = getIDOfComposite(this);
|
||||
var isRender = fnName === '_renderValidatedComponent';
|
||||
var isMount = fnName === 'mountComponent';
|
||||
|
||||
var mountStack = ReactDefaultPerf._mountStack;
|
||||
|
||||
if (isRender) {
|
||||
addValue(entry.counts, rootNodeID, 1);
|
||||
} else if (isMount) {
|
||||
entry.created[rootNodeID] = true;
|
||||
mountStack.push(0);
|
||||
}
|
||||
|
||||
ReactDefaultPerf._compositeStack.push(rootNodeID);
|
||||
|
||||
start = performanceNow();
|
||||
rv = func.apply(this, args);
|
||||
totalTime = performanceNow() - start;
|
||||
|
||||
ReactDefaultPerf._compositeStack.pop();
|
||||
|
||||
if (isRender) {
|
||||
addValue(entry.render, rootNodeID, totalTime);
|
||||
} else if (isMount) {
|
||||
var subMountTime = mountStack.pop();
|
||||
mountStack[mountStack.length - 1] += totalTime;
|
||||
addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
|
||||
addValue(entry.inclusive, rootNodeID, totalTime);
|
||||
} else {
|
||||
addValue(entry.inclusive, rootNodeID, totalTime);
|
||||
}
|
||||
|
||||
entry.displayNames[rootNodeID] = {
|
||||
current: this.getName(),
|
||||
owner: this._currentElement._owner ?
|
||||
this._currentElement._owner.getName() :
|
||||
'<root>',
|
||||
};
|
||||
|
||||
return rv;
|
||||
} else if (
|
||||
(moduleName === 'ReactDOMComponent' ||
|
||||
moduleName === 'ReactDOMTextComponent') &&
|
||||
(fnName === 'mountComponent' ||
|
||||
fnName === 'receiveComponent')) {
|
||||
|
||||
rv = func.apply(this, args);
|
||||
entry.hierarchy[getID(this)] =
|
||||
ReactDefaultPerf._compositeStack.slice();
|
||||
return rv;
|
||||
} else {
|
||||
return func.apply(this, args);
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactDefaultPerf;
|
||||
@@ -1,214 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactDefaultPerfAnalysis
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
// Don't try to save users less than 1.2ms (a number I made up)
|
||||
var DONT_CARE_THRESHOLD = 1.2;
|
||||
var DOM_OPERATION_TYPES = {
|
||||
'_mountImageIntoNode': 'set innerHTML',
|
||||
INSERT_MARKUP: 'set innerHTML',
|
||||
MOVE_EXISTING: 'move',
|
||||
REMOVE_NODE: 'remove',
|
||||
SET_MARKUP: 'set innerHTML',
|
||||
TEXT_CONTENT: 'set textContent',
|
||||
'setValueForProperty': 'update attribute',
|
||||
'setValueForAttribute': 'update attribute',
|
||||
'deleteValueForProperty': 'remove attribute',
|
||||
'setValueForStyles': 'update styles',
|
||||
'replaceNodeWithMarkup': 'replace',
|
||||
'replaceDelimitedText': 'replace',
|
||||
};
|
||||
|
||||
function getTotalTime(measurements) {
|
||||
// TODO: return number of DOM ops? could be misleading.
|
||||
// TODO: measure dropped frames after reconcile?
|
||||
// TODO: log total time of each reconcile and the top-level component
|
||||
// class that triggered it.
|
||||
var totalTime = 0;
|
||||
for (var i = 0; i < measurements.length; i++) {
|
||||
var measurement = measurements[i];
|
||||
totalTime += measurement.totalTime;
|
||||
}
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
function getDOMSummary(measurements) {
|
||||
var items = [];
|
||||
measurements.forEach(function(measurement) {
|
||||
Object.keys(measurement.writes).forEach(function(id) {
|
||||
measurement.writes[id].forEach(function(write) {
|
||||
items.push({
|
||||
id: id,
|
||||
type: DOM_OPERATION_TYPES[write.type] || write.type,
|
||||
args: write.args,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return items;
|
||||
}
|
||||
|
||||
function getExclusiveSummary(measurements) {
|
||||
var candidates = {};
|
||||
var displayName;
|
||||
|
||||
for (var i = 0; i < measurements.length; i++) {
|
||||
var measurement = measurements[i];
|
||||
var allIDs = Object.assign(
|
||||
{},
|
||||
measurement.exclusive,
|
||||
measurement.inclusive
|
||||
);
|
||||
|
||||
for (var id in allIDs) {
|
||||
displayName = measurement.displayNames[id].current;
|
||||
|
||||
candidates[displayName] = candidates[displayName] || {
|
||||
componentName: displayName,
|
||||
inclusive: 0,
|
||||
exclusive: 0,
|
||||
render: 0,
|
||||
count: 0,
|
||||
};
|
||||
if (measurement.render[id]) {
|
||||
candidates[displayName].render += measurement.render[id];
|
||||
}
|
||||
if (measurement.exclusive[id]) {
|
||||
candidates[displayName].exclusive += measurement.exclusive[id];
|
||||
}
|
||||
if (measurement.inclusive[id]) {
|
||||
candidates[displayName].inclusive += measurement.inclusive[id];
|
||||
}
|
||||
if (measurement.counts[id]) {
|
||||
candidates[displayName].count += measurement.counts[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now make a sorted array with the results.
|
||||
var arr = [];
|
||||
for (displayName in candidates) {
|
||||
if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
|
||||
arr.push(candidates[displayName]);
|
||||
}
|
||||
}
|
||||
|
||||
arr.sort(function(a, b) {
|
||||
return b.exclusive - a.exclusive;
|
||||
});
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
function getInclusiveSummary(measurements, onlyClean) {
|
||||
var candidates = {};
|
||||
var inclusiveKey;
|
||||
|
||||
for (var i = 0; i < measurements.length; i++) {
|
||||
var measurement = measurements[i];
|
||||
var allIDs = Object.assign(
|
||||
{},
|
||||
measurement.exclusive,
|
||||
measurement.inclusive
|
||||
);
|
||||
var cleanComponents;
|
||||
|
||||
if (onlyClean) {
|
||||
cleanComponents = getUnchangedComponents(measurement);
|
||||
}
|
||||
|
||||
for (var id in allIDs) {
|
||||
if (onlyClean && !cleanComponents[id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var displayName = measurement.displayNames[id];
|
||||
|
||||
// Inclusive time is not useful for many components without knowing where
|
||||
// they are instantiated. So we aggregate inclusive time with both the
|
||||
// owner and current displayName as the key.
|
||||
inclusiveKey = displayName.owner + ' > ' + displayName.current;
|
||||
|
||||
candidates[inclusiveKey] = candidates[inclusiveKey] || {
|
||||
componentName: inclusiveKey,
|
||||
time: 0,
|
||||
count: 0,
|
||||
};
|
||||
|
||||
if (measurement.inclusive[id]) {
|
||||
candidates[inclusiveKey].time += measurement.inclusive[id];
|
||||
}
|
||||
if (measurement.counts[id]) {
|
||||
candidates[inclusiveKey].count += measurement.counts[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now make a sorted array with the results.
|
||||
var arr = [];
|
||||
for (inclusiveKey in candidates) {
|
||||
if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
|
||||
arr.push(candidates[inclusiveKey]);
|
||||
}
|
||||
}
|
||||
|
||||
arr.sort(function(a, b) {
|
||||
return b.time - a.time;
|
||||
});
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
function getUnchangedComponents(measurement) {
|
||||
// For a given reconcile, look at which components did not actually
|
||||
// render anything to the DOM and return a mapping of their ID to
|
||||
// the amount of time it took to render the entire subtree.
|
||||
var cleanComponents = {};
|
||||
var writes = measurement.writes;
|
||||
var hierarchy = measurement.hierarchy;
|
||||
var dirtyComposites = {};
|
||||
Object.keys(writes).forEach(function(id) {
|
||||
writes[id].forEach(function(write) {
|
||||
// Root mounting (innerHTML set) is recorded with an ID of ''
|
||||
if (id !== '' && hierarchy.hasOwnProperty(id)) {
|
||||
hierarchy[id].forEach((c) => dirtyComposites[c] = true);
|
||||
}
|
||||
});
|
||||
});
|
||||
var allIDs = Object.assign({}, measurement.exclusive, measurement.inclusive);
|
||||
|
||||
for (var id in allIDs) {
|
||||
var isDirty = false;
|
||||
// See if any of the DOM operations applied to this component's subtree.
|
||||
if (dirtyComposites[id]) {
|
||||
isDirty = true;
|
||||
}
|
||||
// check if component newly created
|
||||
if (measurement.created[id]) {
|
||||
isDirty = true;
|
||||
}
|
||||
if (!isDirty && measurement.counts[id] > 0) {
|
||||
cleanComponents[id] = true;
|
||||
}
|
||||
}
|
||||
return cleanComponents;
|
||||
}
|
||||
|
||||
var ReactDefaultPerfAnalysis = {
|
||||
getExclusiveSummary: getExclusiveSummary,
|
||||
getInclusiveSummary: getInclusiveSummary,
|
||||
getDOMSummary: getDOMSummary,
|
||||
getTotalTime: getTotalTime,
|
||||
};
|
||||
|
||||
module.exports = ReactDefaultPerfAnalysis;
|
||||
@@ -1,100 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactPerf
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ReactPerf is a general AOP system designed to measure performance. This
|
||||
* module only has the hooks: see ReactDefaultPerf for the analysis tool.
|
||||
* See also https://facebook.github.io/react/docs/perf.html
|
||||
*/
|
||||
var ReactPerf = {
|
||||
/**
|
||||
* Boolean to enable/disable measurement. Set to false by default to prevent
|
||||
* accidental logging and perf loss.
|
||||
*/
|
||||
enableMeasure: false,
|
||||
|
||||
/**
|
||||
* Holds onto the measure function in use. By default, don't measure
|
||||
* anything, but we'll override this if we inject a measure function.
|
||||
*/
|
||||
storedMeasure: _noMeasure,
|
||||
|
||||
/**
|
||||
* @param {object} object
|
||||
* @param {string} objectName
|
||||
* @param {object<string>} methodNames
|
||||
*/
|
||||
measureMethods: function(object, objectName, methodNames) {
|
||||
if (__DEV__) {
|
||||
for (var key in methodNames) {
|
||||
if (!methodNames.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
object[key] = ReactPerf.measure(
|
||||
objectName,
|
||||
methodNames[key],
|
||||
object[key]
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Use this to wrap methods you want to measure. Zero overhead in production.
|
||||
*
|
||||
* @param {string} objName
|
||||
* @param {string} fnName
|
||||
* @param {function} func
|
||||
* @return {function}
|
||||
*/
|
||||
measure: function(objName, fnName, func) {
|
||||
if (__DEV__) {
|
||||
var measuredFunc = null;
|
||||
var wrapper = function() {
|
||||
if (ReactPerf.enableMeasure) {
|
||||
if (!measuredFunc) {
|
||||
measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
|
||||
}
|
||||
return measuredFunc.apply(this, arguments);
|
||||
}
|
||||
return func.apply(this, arguments);
|
||||
};
|
||||
wrapper.displayName = objName + '_' + fnName;
|
||||
return wrapper;
|
||||
}
|
||||
return func;
|
||||
},
|
||||
|
||||
injection: {
|
||||
/**
|
||||
* @param {function} measure
|
||||
*/
|
||||
injectMeasure: function(measure) {
|
||||
ReactPerf.storedMeasure = measure;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Simply passes through the measured function, without measuring it.
|
||||
*
|
||||
* @param {string} objName
|
||||
* @param {string} fnName
|
||||
* @param {function} func
|
||||
* @return {function}
|
||||
*/
|
||||
function _noMeasure(objName, fnName, func) {
|
||||
return func;
|
||||
}
|
||||
|
||||
module.exports = ReactPerf;
|
||||
@@ -1,299 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('ReactDefaultPerf', function() {
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactDOMFeatureFlags;
|
||||
var ReactDefaultPerf;
|
||||
var ReactTestUtils;
|
||||
var ReactDefaultPerfAnalysis;
|
||||
|
||||
var App;
|
||||
var Box;
|
||||
var Div;
|
||||
|
||||
beforeEach(function() {
|
||||
var now = 0;
|
||||
jest.setMock('fbjs/lib/performanceNow', function() {
|
||||
return now++;
|
||||
});
|
||||
|
||||
if (typeof console.table !== 'function') {
|
||||
console.table = () => {};
|
||||
console.table.isFake = true;
|
||||
}
|
||||
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
|
||||
ReactDefaultPerf = require('ReactDefaultPerf');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
|
||||
|
||||
App = React.createClass({
|
||||
render: function() {
|
||||
return <div><Box /><Box flip={this.props.flipSecond} /></div>;
|
||||
},
|
||||
});
|
||||
|
||||
Box = React.createClass({
|
||||
render: function() {
|
||||
return <div key={!!this.props.flip}><input /></div>;
|
||||
},
|
||||
});
|
||||
|
||||
// ReactPerf only measures composites, so we put everything in one.
|
||||
Div = React.createClass({
|
||||
render: function() {
|
||||
return <div {...this.props} />;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
if (console.table.isFake) {
|
||||
delete console.table;
|
||||
}
|
||||
});
|
||||
|
||||
function measure(fn) {
|
||||
ReactDefaultPerf.start();
|
||||
fn();
|
||||
ReactDefaultPerf.stop();
|
||||
return ReactDefaultPerf.getLastMeasurements().__unstable_this_format_will_change;
|
||||
}
|
||||
|
||||
it('should count no-op update as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<App />, container);
|
||||
var measurements = measure(() => {
|
||||
ReactDOM.render(<App />, container);
|
||||
});
|
||||
|
||||
var summary = ReactDefaultPerf.getWasted(measurements);
|
||||
expect(summary.length).toBe(2);
|
||||
|
||||
/*eslint-disable dot-notation */
|
||||
|
||||
expect(summary[0]['Owner > component']).toBe('<root> > App');
|
||||
expect(summary[0]['Wasted time (ms)']).not.toBe(0);
|
||||
expect(summary[0]['Instances']).toBe(1);
|
||||
|
||||
expect(summary[1]['Owner > component']).toBe('App > Box');
|
||||
expect(summary[1]['Wasted time (ms)']).not.toBe(0);
|
||||
expect(summary[1]['Instances']).toBe(2);
|
||||
|
||||
/*eslint-enable dot-notation */
|
||||
});
|
||||
|
||||
it('should count no-op update in child as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<App />, container);
|
||||
|
||||
// Here, we add a Box -- two of the <Box /> updates are wasted time (but the
|
||||
// addition of the third is not)
|
||||
var measurements = measure(() => {
|
||||
ReactDOM.render(<App flipSecond={true} />, container);
|
||||
});
|
||||
|
||||
var summary = ReactDefaultPerf.getWasted(measurements);
|
||||
expect(summary.length).toBe(1);
|
||||
|
||||
/*eslint-disable dot-notation */
|
||||
|
||||
expect(summary[0]['Owner > component']).toBe('App > Box');
|
||||
expect(summary[0]['Wasted time (ms)']).not.toBe(0);
|
||||
expect(summary[0]['Instances']).toBe(1);
|
||||
|
||||
/*eslint-enable dot-notation */
|
||||
});
|
||||
|
||||
function expectNoWaste(fn) {
|
||||
var measurements = measure(fn);
|
||||
var summary = ReactDefaultPerf.getWasted(measurements);
|
||||
expect(summary).toEqual([]);
|
||||
}
|
||||
|
||||
it('should not count initial render as waste', function() {
|
||||
expectNoWaste(() => {
|
||||
ReactTestUtils.renderIntoDocument(<App />);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count unmount as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div>hello</Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count content update as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div>hello</Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div>hello world</Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count child addition as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div><span /></Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div><span /><span /></Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count child removal as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div><span /><span /></Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div><span /></Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count property update as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div className="yellow">hey</Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div className="blue">hey</Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count style update as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div style={{color: 'yellow'}}>hey</Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div style={{color: 'blue'}}>hey</Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count property removal as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div className="yellow">hey</Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div>hey</Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count raw HTML update as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
<Div dangerouslySetInnerHTML={{__html: 'me'}} />,
|
||||
container
|
||||
);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(
|
||||
<Div dangerouslySetInnerHTML={{__html: 'you'}} />,
|
||||
container
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count child reordering as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div><div key="A" /><div key="B" /></Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div><div key="B" /><div key="A" /></Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not count text update as waste', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div>{'hello'}{'world'}</Div>, container);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(<Div>{'hello'}{'friend'}</Div>, container);
|
||||
});
|
||||
});
|
||||
|
||||
it('putListener should not be instrumented', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div onClick={function() {}}>hey</Div>, container);
|
||||
var measurements = measure(() => {
|
||||
ReactDOM.render(<Div onClick={function() {}}>hey</Div>, container);
|
||||
});
|
||||
|
||||
var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
|
||||
expect(summary).toEqual([]);
|
||||
});
|
||||
|
||||
it('deleteListener should not be instrumented', function() {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Div onClick={function() {}}>hey</Div>, container);
|
||||
var measurements = measure(() => {
|
||||
ReactDOM.render(<Div>hey</Div>, container);
|
||||
});
|
||||
|
||||
var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
|
||||
expect(summary).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not fail on input change events', function() {
|
||||
var container = document.createElement('div');
|
||||
var onChange = () => {};
|
||||
var input = ReactDOM.render(
|
||||
<input checked={true} onChange={onChange} />,
|
||||
container
|
||||
);
|
||||
expectNoWaste(() => {
|
||||
ReactTestUtils.Simulate.change(input);
|
||||
});
|
||||
});
|
||||
|
||||
it('should print a table after calling printOperations', function() {
|
||||
var container = document.createElement('div');
|
||||
var measurements = measure(() => {
|
||||
ReactDOM.render(<Div>hey</Div>, container);
|
||||
});
|
||||
spyOn(console, 'table');
|
||||
ReactDefaultPerf.printOperations(measurements);
|
||||
expect(console.table.calls.length).toBe(1);
|
||||
expect(console.table.argsForCall[0][0]).toEqual([{
|
||||
'data-reactid': '',
|
||||
type: 'set innerHTML',
|
||||
args: ReactDOMFeatureFlags.useCreateElement ?
|
||||
'{"node":"<not serializable>","children":[],"html":null,"text":null}' :
|
||||
'"<div data-reactroot=\\"\\" data-reactid=\\"1\\">hey</div>"',
|
||||
}]);
|
||||
});
|
||||
|
||||
it('warns once when using getMeasurementsSummaryMap', function() {
|
||||
var measurements = measure(() => {});
|
||||
spyOn(console, 'error');
|
||||
ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
|
||||
expect(console.error.calls.length).toBe(1);
|
||||
expect(console.error.argsForCall[0][0]).toContain(
|
||||
'`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
|
||||
'`ReactPerf.getWasted(...)` instead.'
|
||||
);
|
||||
|
||||
ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
|
||||
expect(console.error.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('warns once when using printDOM', function() {
|
||||
var measurements = measure(() => {});
|
||||
spyOn(console, 'error');
|
||||
ReactDefaultPerf.printDOM(measurements);
|
||||
expect(console.error.calls.length).toBe(1);
|
||||
expect(console.error.argsForCall[0][0]).toContain(
|
||||
'`ReactPerf.printDOM(...)` is deprecated. Use ' +
|
||||
'`ReactPerf.printOperations(...)` instead.'
|
||||
);
|
||||
|
||||
ReactDefaultPerf.printDOM(measurements);
|
||||
expect(console.error.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user