mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
Merge pull request #5550 from spicyj/cc-speed
Make createClass 10-15% faster on complex specs
This commit is contained in:
243
scripts/bench/bench-createclass.js
Normal file
243
scripts/bench/bench-createclass.js
Normal file
@@ -0,0 +1,243 @@
|
||||
React.createClass({
|
||||
displayName: "UnimplementedView",
|
||||
setNativeProps: function() {},
|
||||
render: function() {},
|
||||
});
|
||||
var mixin1 = {
|
||||
measure: function() {},
|
||||
measureLayout: function() {},
|
||||
setNativeProps: function() {},
|
||||
focus: function() {},
|
||||
blur: function() {},
|
||||
componentWillMount: function() {},
|
||||
componentWillReceiveProps: function() {},
|
||||
};
|
||||
React.createClass({
|
||||
displayName: "View",
|
||||
mixins: [mixin1],
|
||||
viewConfig: {uiViewClassName: "RCTView", validAttributes: null},
|
||||
statics: {AccessibilityTraits: null, AccessibilityComponentType: null},
|
||||
propTypes: {accessible: function() {}, accessibilityLabel: function() {}, accessibilityComponentType: function() {}, accessibilityLiveRegion: function() {}, importantForAccessibility: function() {}, accessibilityTraits: function() {}, onAccessibilityTap: function() {}, onMagicTap: function() {}, testID: function() {}, onResponderGrant: function() {}, onResponderMove: function() {}, onResponderReject: function() {}, onResponderRelease: function() {}, onResponderTerminate: function() {}, onResponderTerminationRequest: function() {}, onStartShouldSetResponder: function() {}, onStartShouldSetResponderCapture: function() {}, onMoveShouldSetResponder: function() {}, onMoveShouldSetResponderCapture: function() {}, onLayout: function() {}, pointerEvents: function() {}, style: function() {}, removeClippedSubviews: function() {}, renderToHardwareTextureAndroid: function() {}, shouldRasterizeIOS: function() {}, collapsable: function() {}, needsOffscreenAlphaCompositing: function() {}},
|
||||
render: function() {},
|
||||
});
|
||||
var mixin2 = {
|
||||
componentWillUnmount: function() {},
|
||||
setTimeout: function() {},
|
||||
clearTimeout: function() {},
|
||||
setInterval: function() {},
|
||||
clearInterval: function() {},
|
||||
setImmediate: function() {},
|
||||
clearImmediate: function() {},
|
||||
requestAnimationFrame: function() {},
|
||||
cancelAnimationFrame: function() {},
|
||||
};
|
||||
var mixin3 = {
|
||||
componentWillUnmount: function() {},
|
||||
_interactionMixinHandles: {},
|
||||
createInteractionHandle: function() {},
|
||||
clearInteractionHandle: function() {},
|
||||
runAfterInteractions: function() {},
|
||||
};
|
||||
var mixin4 = {
|
||||
componentWillMount: function() {},
|
||||
componentWillUnmount: function() {},
|
||||
addListenerOn: function() {},
|
||||
};
|
||||
React.createClass({
|
||||
displayName: "Navigator",
|
||||
propTypes: {configureScene: function() {}, renderScene: function() {}, initialRoute: function() {}, initialRouteStack: function() {}, onWillFocus: function() {}, onDidFocus: function() {}, navigationBar: function() {}, navigator: function() {}, sceneStyle: function() {}},
|
||||
statics: {BreadcrumbNavigationBar: null, NavigationBar: null, SceneConfigs: null},
|
||||
mixins: [mixin2, mixin3, mixin4],
|
||||
getDefaultProps: function() {},
|
||||
getInitialState: function() {},
|
||||
componentWillMount: function() {},
|
||||
componentDidMount: function() {},
|
||||
componentWillUnmount: function() {},
|
||||
immediatelyResetRouteStack: function() {},
|
||||
_transitionTo: function() {},
|
||||
_handleSpringUpdate: function() {},
|
||||
_completeTransition: function() {},
|
||||
_emitDidFocus: function() {},
|
||||
_emitWillFocus: function() {},
|
||||
_hideScenes: function() {},
|
||||
_disableScene: function() {},
|
||||
_enableScene: function() {},
|
||||
_onAnimationStart: function() {},
|
||||
_onAnimationEnd: function() {},
|
||||
_setRenderSceneToHardwareTextureAndroid: function() {},
|
||||
_handleTouchStart: function() {},
|
||||
_handleMoveShouldSetPanResponder: function() {},
|
||||
_doesGestureOverswipe: function() {},
|
||||
_deltaForGestureAction: function() {},
|
||||
_handlePanResponderRelease: function() {},
|
||||
_handlePanResponderTerminate: function() {},
|
||||
_attachGesture: function() {},
|
||||
_detachGesture: function() {},
|
||||
_handlePanResponderMove: function() {},
|
||||
_moveAttachedGesture: function() {},
|
||||
_matchGestureAction: function() {},
|
||||
_transitionSceneStyle: function() {},
|
||||
_transitionBetween: function() {},
|
||||
_handleResponderTerminationRequest: function() {},
|
||||
_getDestIndexWithinBounds: function() {},
|
||||
_jumpN: function() {},
|
||||
jumpTo: function() {},
|
||||
jumpForward: function() {},
|
||||
jumpBack: function() {},
|
||||
push: function() {},
|
||||
_popN: function() {},
|
||||
pop: function() {},
|
||||
replaceAtIndex: function() {},
|
||||
replace: function() {},
|
||||
replacePrevious: function() {},
|
||||
popToTop: function() {},
|
||||
popToRoute: function() {},
|
||||
replacePreviousAndPop: function() {},
|
||||
resetTo: function() {},
|
||||
getCurrentRoutes: function() {},
|
||||
_cleanScenesPastIndex: function() {},
|
||||
_renderScene: function() {},
|
||||
_renderNavigationBar: function() {},
|
||||
render: function() {},
|
||||
_getNavigationContext: function() {},
|
||||
});
|
||||
var mixin5 = {
|
||||
mixins: [mixin4],
|
||||
statics: {DecelerationRate: null},
|
||||
scrollResponderMixinGetInitialState: function() {},
|
||||
scrollResponderHandleScrollShouldSetResponder: function() {},
|
||||
scrollResponderHandleStartShouldSetResponder: function() {},
|
||||
scrollResponderHandleStartShouldSetResponderCapture: function() {},
|
||||
scrollResponderHandleResponderReject: function() {},
|
||||
scrollResponderHandleTerminationRequest: function() {},
|
||||
scrollResponderHandleTouchEnd: function() {},
|
||||
scrollResponderHandleResponderRelease: function() {},
|
||||
scrollResponderHandleScroll: function() {},
|
||||
scrollResponderHandleResponderGrant: function() {},
|
||||
scrollResponderHandleScrollBeginDrag: function() {},
|
||||
scrollResponderHandleScrollEndDrag: function() {},
|
||||
scrollResponderHandleMomentumScrollBegin: function() {},
|
||||
scrollResponderHandleMomentumScrollEnd: function() {},
|
||||
scrollResponderHandleTouchStart: function() {},
|
||||
scrollResponderHandleTouchMove: function() {},
|
||||
scrollResponderIsAnimating: function() {},
|
||||
scrollResponderScrollTo: function() {},
|
||||
scrollResponderScrollWithouthAnimationTo: function() {},
|
||||
scrollResponderZoomTo: function() {},
|
||||
scrollResponderScrollNativeHandleToKeyboard: function() {},
|
||||
scrollResponderInputMeasureAndScrollToKeyboard: function() {},
|
||||
scrollResponderTextInputFocusError: function() {},
|
||||
componentWillMount: function() {},
|
||||
scrollResponderKeyboardWillShow: function() {},
|
||||
scrollResponderKeyboardWillHide: function() {},
|
||||
scrollResponderKeyboardDidShow: function() {},
|
||||
scrollResponderKeyboardDidHide: function() {},
|
||||
};
|
||||
React.createClass({
|
||||
displayName: "ScrollView",
|
||||
propTypes: {accessible: function() {}, accessibilityLabel: function() {}, accessibilityComponentType: function() {}, accessibilityLiveRegion: function() {}, importantForAccessibility: function() {}, accessibilityTraits: function() {}, onAccessibilityTap: function() {}, onMagicTap: function() {}, testID: function() {}, onResponderGrant: function() {}, onResponderMove: function() {}, onResponderReject: function() {}, onResponderRelease: function() {}, onResponderTerminate: function() {}, onResponderTerminationRequest: function() {}, onStartShouldSetResponder: function() {}, onStartShouldSetResponderCapture: function() {}, onMoveShouldSetResponder: function() {}, onMoveShouldSetResponderCapture: function() {}, onLayout: function() {}, pointerEvents: function() {}, style: function() {}, removeClippedSubviews: function() {}, renderToHardwareTextureAndroid: function() {}, shouldRasterizeIOS: function() {}, collapsable: function() {}, needsOffscreenAlphaCompositing: function() {}, automaticallyAdjustContentInsets: function() {}, contentInset: function() {}, contentOffset: function() {}, bounces: function() {}, bouncesZoom: function() {}, alwaysBounceHorizontal: function() {}, alwaysBounceVertical: function() {}, centerContent: function() {}, contentContainerStyle: function() {}, decelerationRate: function() {}, horizontal: function() {}, directionalLockEnabled: function() {}, canCancelContentTouches: function() {}, keyboardDismissMode: function() {}, keyboardShouldPersistTaps: function() {}, maximumZoomScale: function() {}, minimumZoomScale: function() {}, onScroll: function() {}, onScrollAnimationEnd: function() {}, onContentSizeChange: function() {}, pagingEnabled: function() {}, scrollEnabled: function() {}, scrollEventThrottle: function() {}, scrollIndicatorInsets: function() {}, scrollsToTop: function() {}, showsHorizontalScrollIndicator: function() {}, showsVerticalScrollIndicator: function() {}, stickyHeaderIndices: function() {}, snapToInterval: function() {}, snapToAlignment: function() {}, zoomScale: function() {}, onRefreshStart: function() {}},
|
||||
mixins: [mixin5],
|
||||
getInitialState: function() {},
|
||||
setNativeProps: function() {},
|
||||
endRefreshing: function() {},
|
||||
getScrollResponder: function() {},
|
||||
getInnerViewNode: function() {},
|
||||
scrollTo: function() {},
|
||||
scrollWithoutAnimationTo: function() {},
|
||||
handleScroll: function() {},
|
||||
_handleContentOnLayout: function() {},
|
||||
render: function() {},
|
||||
});
|
||||
var mixin6 = {
|
||||
componentWillUnmount: function() {},
|
||||
setTimeout: function() {},
|
||||
clearTimeout: function() {},
|
||||
setInterval: function() {},
|
||||
clearInterval: function() {},
|
||||
setImmediate: function() {},
|
||||
clearImmediate: function() {},
|
||||
requestAnimationFrame: function() {},
|
||||
cancelAnimationFrame: function() {},
|
||||
};
|
||||
React.createClass({
|
||||
displayName: "AdsManagerTabsModalView",
|
||||
contextTypes: {navigation: function() {}},
|
||||
mixins: [mixin6, mixin4],
|
||||
getDefaultProps: function() {},
|
||||
getInitialState: function() {},
|
||||
componentWillMount: function() {},
|
||||
componentDidMount: function() {},
|
||||
componentWillUnmount: function() {},
|
||||
onTabSelect: function() {},
|
||||
_handleConnectivityChange: function() {},
|
||||
_onTabTap: function() {},
|
||||
startCreateFlow: function() {},
|
||||
render: function() {},
|
||||
_renderTabs: function() {},
|
||||
_onAdCreated: function() {},
|
||||
_onRemoteNotification: function() {},
|
||||
_setAccountFromURL: function() {},
|
||||
_updateBadgeCount: function() {},
|
||||
_onRetry: function() {},
|
||||
_getUnseenNotifsCount: function() {},
|
||||
_pushNotifPermalink: function() {},
|
||||
_onMobileConfigsLoadDone: function() {},
|
||||
_getAccountRoute: function() {},
|
||||
_getNotifsRoute: function() {},
|
||||
_getSettingsRoute: function() {},
|
||||
_getCampaignsRoute: function() {},
|
||||
_getNavStack: function() {},
|
||||
_onAccountChanged: function() {},
|
||||
_onHelpCenterRequested: function() {},
|
||||
_onGlobalError: function() {},
|
||||
_onGlobalErrorToastDidClose: function() {},
|
||||
_onShowNUX: function() {},
|
||||
_closeToastAndPopover: function() {},
|
||||
_onTabLayout: function() {},
|
||||
_onRootNavigationWillChange: function() {},
|
||||
_handleOpenURL: function() {},
|
||||
_updateAccountIDFromInLink: function() {},
|
||||
_pushInLink: function() {},
|
||||
_pushExternalRoute: function() {},
|
||||
_canPushExernalRoute: function() {},
|
||||
_hasAccountTab: function() {},
|
||||
_hasCampaignsTab: function() {},
|
||||
_getTabForURL: function() {},
|
||||
_getTabForExternalRoute: function() {},
|
||||
});
|
||||
React.createClass({
|
||||
displayName: "ActionBarButton",
|
||||
mixins: [mixin1, mixin6],
|
||||
propTypes: {label: function() {}, iconOnly: function() {}, imageSource: function() {}, style: function() {}, onContentMeasured: function() {}, onPress: function() {}},
|
||||
componentDidMount: function() {},
|
||||
render: function() {},
|
||||
});
|
||||
React.createClass({
|
||||
displayName: "ListView",
|
||||
mixins: [mixin5, mixin2],
|
||||
statics: {DataSource: null},
|
||||
propTypes: {accessible: function() {}, accessibilityLabel: function() {}, accessibilityComponentType: function() {}, accessibilityLiveRegion: function() {}, importantForAccessibility: function() {}, accessibilityTraits: function() {}, onAccessibilityTap: function() {}, onMagicTap: function() {}, testID: function() {}, onResponderGrant: function() {}, onResponderMove: function() {}, onResponderReject: function() {}, onResponderRelease: function() {}, onResponderTerminate: function() {}, onResponderTerminationRequest: function() {}, onStartShouldSetResponder: function() {}, onStartShouldSetResponderCapture: function() {}, onMoveShouldSetResponder: function() {}, onMoveShouldSetResponderCapture: function() {}, onLayout: function() {}, pointerEvents: function() {}, style: function() {}, removeClippedSubviews: function() {}, renderToHardwareTextureAndroid: function() {}, shouldRasterizeIOS: function() {}, collapsable: function() {}, needsOffscreenAlphaCompositing: function() {}, automaticallyAdjustContentInsets: function() {}, contentInset: function() {}, contentOffset: function() {}, bounces: function() {}, bouncesZoom: function() {}, alwaysBounceHorizontal: function() {}, alwaysBounceVertical: function() {}, centerContent: function() {}, contentContainerStyle: function() {}, decelerationRate: function() {}, horizontal: function() {}, directionalLockEnabled: function() {}, canCancelContentTouches: function() {}, keyboardDismissMode: function() {}, keyboardShouldPersistTaps: function() {}, maximumZoomScale: function() {}, minimumZoomScale: function() {}, onScroll: function() {}, onScrollAnimationEnd: function() {}, onContentSizeChange: function() {}, pagingEnabled: function() {}, scrollEnabled: function() {}, scrollEventThrottle: function() {}, scrollIndicatorInsets: function() {}, scrollsToTop: function() {}, showsHorizontalScrollIndicator: function() {}, showsVerticalScrollIndicator: function() {}, stickyHeaderIndices: function() {}, snapToInterval: function() {}, snapToAlignment: function() {}, zoomScale: function() {}, onRefreshStart: function() {}, dataSource: function() {}, renderSeparator: function() {}, renderRow: function() {}, initialListSize: function() {}, onEndReached: function() {}, onEndReachedThreshold: function() {}, pageSize: function() {}, renderFooter: function() {}, renderHeader: function() {}, renderSectionHeader: function() {}, renderScrollComponent: function() {}, scrollRenderAheadDistance: function() {}, onChangeVisibleRows: function() {}},
|
||||
getMetrics: function() {},
|
||||
getScrollResponder: function() {},
|
||||
setNativeProps: function() {},
|
||||
getDefaultProps: function() {},
|
||||
getInitialState: function() {},
|
||||
getInnerViewNode: function() {},
|
||||
componentWillMount: function() {},
|
||||
componentDidMount: function() {},
|
||||
componentWillReceiveProps: function() {},
|
||||
componentDidUpdate: function() {},
|
||||
onRowHighlighted: function() {},
|
||||
render: function() {},
|
||||
_measureAndUpdateScrollProps: function() {},
|
||||
_onContentSizeChange: function() {},
|
||||
_onLayout: function() {},
|
||||
_setScrollVisibleLength: function() {},
|
||||
_updateChildFrames: function() {},
|
||||
_maybeCallOnEndReached: function() {},
|
||||
_renderMoreRowsIfNeeded: function() {},
|
||||
_pageInNewRows: function() {},
|
||||
_getDistanceFromEnd: function() {},
|
||||
_updateVisibleRows: function() {},
|
||||
_onScroll: function() {},
|
||||
});
|
||||
@@ -402,7 +402,7 @@ function validateTypeDef(Constructor, typeDef, location) {
|
||||
}
|
||||
}
|
||||
|
||||
function validateMethodOverride(proto, name) {
|
||||
function validateMethodOverride(isAlreadyDefined, name) {
|
||||
var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
|
||||
ReactClassInterface[name] :
|
||||
null;
|
||||
@@ -419,7 +419,7 @@ function validateMethodOverride(proto, name) {
|
||||
}
|
||||
|
||||
// Disallow defining methods more than once unless explicitly allowed.
|
||||
if (proto.hasOwnProperty(name)) {
|
||||
if (isAlreadyDefined) {
|
||||
invariant(
|
||||
specPolicy === SpecPolicy.DEFINE_MANY ||
|
||||
specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
|
||||
@@ -453,6 +453,7 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
);
|
||||
|
||||
var proto = Constructor.prototype;
|
||||
var autoBindPairs = proto.__reactAutoBindPairs;
|
||||
|
||||
// By handling mixins before any other properties, we ensure the same
|
||||
// chaining order is applied to methods with DEFINE_MANY policy, whether
|
||||
@@ -472,7 +473,8 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
}
|
||||
|
||||
var property = spec[name];
|
||||
validateMethodOverride(proto, name);
|
||||
var isAlreadyDefined = proto.hasOwnProperty(name);
|
||||
validateMethodOverride(isAlreadyDefined, name);
|
||||
|
||||
if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
|
||||
RESERVED_SPEC_KEYS[name](Constructor, property);
|
||||
@@ -483,7 +485,6 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
// 2. Overridden methods (that were mixed in).
|
||||
var isReactClassMethod =
|
||||
ReactClassInterface.hasOwnProperty(name);
|
||||
var isAlreadyDefined = proto.hasOwnProperty(name);
|
||||
var isFunction = typeof property === 'function';
|
||||
var shouldAutoBind =
|
||||
isFunction &&
|
||||
@@ -492,10 +493,7 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
spec.autobind !== false;
|
||||
|
||||
if (shouldAutoBind) {
|
||||
if (!proto.__reactAutoBindMap) {
|
||||
proto.__reactAutoBindMap = {};
|
||||
}
|
||||
proto.__reactAutoBindMap[name] = property;
|
||||
autoBindPairs.push(name, property);
|
||||
proto[name] = property;
|
||||
} else {
|
||||
if (isAlreadyDefined) {
|
||||
@@ -688,14 +686,14 @@ function bindAutoBindMethod(component, method) {
|
||||
* @param {object} component Component whose method is going to be bound.
|
||||
*/
|
||||
function bindAutoBindMethods(component) {
|
||||
for (var autoBindKey in component.__reactAutoBindMap) {
|
||||
if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
|
||||
var method = component.__reactAutoBindMap[autoBindKey];
|
||||
component[autoBindKey] = bindAutoBindMethod(
|
||||
component,
|
||||
method
|
||||
);
|
||||
}
|
||||
var pairs = component.__reactAutoBindPairs;
|
||||
for (var i = 0; i < pairs.length; i += 2) {
|
||||
var autoBindKey = pairs[i];
|
||||
var method = pairs[i + 1];
|
||||
component[autoBindKey] = bindAutoBindMethod(
|
||||
component,
|
||||
method
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,7 +760,7 @@ var ReactClass = {
|
||||
}
|
||||
|
||||
// Wire up auto-binding
|
||||
if (this.__reactAutoBindMap) {
|
||||
if (this.__reactAutoBindPairs.length) {
|
||||
bindAutoBindMethods(this);
|
||||
}
|
||||
|
||||
@@ -796,6 +794,7 @@ var ReactClass = {
|
||||
};
|
||||
Constructor.prototype = new ReactClassComponent();
|
||||
Constructor.prototype.constructor = Constructor;
|
||||
Constructor.prototype.__reactAutoBindPairs = [];
|
||||
|
||||
injectedMixins.forEach(
|
||||
mixSpecIntoComponent.bind(null, Constructor)
|
||||
|
||||
Reference in New Issue
Block a user