mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-23 11:57:46 +08:00
Add option to track when we're showing blankness during fast scrolling
Summary: If tracking is enabled and the sampling check passes on a scroll or layout event, we compare the scroll offset to the layout of the rendered items. If the items don't cover the visible area of the list, we fire an `onFillRateExceeded` call with relevant stats for logging the event through an analytics pipeline. The measurement methodology is a little jank because everything is async, but it seems directionally useful for getting ballpark numbers, catching regressions, and tracking improvements. Benchmark testing shows a ~2014 MotoX starts hitting the fill rate limit at about 2500 px / sec, which is pretty fast scrolling. This also reworks our frame rate stuff so we can use a shared `SceneTracking` thing and track blankness globally. Reviewed By: bvaughn Differential Revision: D4806867 fbshipit-source-id: 119bf177463c8c3aa51fa13d1a9d03b1a96042aa
This commit is contained in:
committed by
Facebook Github Bot
parent
b5327dd388
commit
f72d9dd08b
@@ -12,6 +12,7 @@
|
||||
'use strict';
|
||||
|
||||
const Batchinator = require('Batchinator');
|
||||
const FillRateHelper = require('FillRateHelper');
|
||||
const React = require('React');
|
||||
const ReactNative = require('ReactNative');
|
||||
const RefreshControl = require('RefreshControl');
|
||||
@@ -27,6 +28,7 @@ const {computeWindowedRenderLimits} = require('VirtualizeUtils');
|
||||
import type {ViewabilityConfig, ViewToken} from 'ViewabilityHelper';
|
||||
|
||||
type Item = any;
|
||||
|
||||
type renderItemType = (info: {item: Item, index: number}) => ?React.Element<any>;
|
||||
|
||||
type RequiredProps = {
|
||||
@@ -301,6 +303,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
'to support native onScroll events with useNativeDriver',
|
||||
);
|
||||
|
||||
this._fillRateHelper = new FillRateHelper(this._getFrameMetrics);
|
||||
this._updateCellsToRenderBatcher = new Batchinator(
|
||||
this._updateCellsToRender,
|
||||
this.props.updateCellsBatchingPeriod,
|
||||
@@ -366,6 +369,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {ListFooterComponent, ListHeaderComponent} = this.props;
|
||||
const {data, disableVirtualization, horizontal} = this.props;
|
||||
@@ -481,6 +485,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
_hasWarned = {};
|
||||
_highestMeasuredFrameIndex = 0;
|
||||
_headerLength = 0;
|
||||
_fillRateHelper: FillRateHelper;
|
||||
_frames = {};
|
||||
_footerLength = 0;
|
||||
_scrollMetrics = {
|
||||
@@ -520,6 +525,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
} else {
|
||||
this._frames[cellKey].inLayout = true;
|
||||
}
|
||||
this._sampleFillRate('onCellLayout');
|
||||
}
|
||||
|
||||
_onCellUnmount = (cellKey: string) => {
|
||||
@@ -606,6 +612,15 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
this._updateCellsToRenderBatcher.schedule();
|
||||
};
|
||||
|
||||
_sampleFillRate(sampleType: string) {
|
||||
this._fillRateHelper.computeInfoSampled(
|
||||
sampleType,
|
||||
this.props,
|
||||
this.state,
|
||||
this._scrollMetrics,
|
||||
);
|
||||
}
|
||||
|
||||
_onScroll = (e: Object) => {
|
||||
if (this.props.onScroll) {
|
||||
this.props.onScroll(e);
|
||||
@@ -629,6 +644,9 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
const velocity = dOffset / dt;
|
||||
this._scrollMetrics = {contentLength, dt, offset, timestamp, velocity, visibleLength};
|
||||
const {data, getItemCount, onEndReached, onEndReachedThreshold, windowSize} = this.props;
|
||||
|
||||
this._sampleFillRate('onScroll');
|
||||
|
||||
this._updateViewableItems(data);
|
||||
if (!data) {
|
||||
return;
|
||||
@@ -667,6 +685,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
this._viewabilityHelper.recordInteraction();
|
||||
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e);
|
||||
};
|
||||
|
||||
_updateCellsToRender = () => {
|
||||
const {data, disableVirtualization, getItemCount, onEndReachedThreshold} = this.props;
|
||||
this._updateViewableItems(data);
|
||||
@@ -717,7 +736,9 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
_getFrameMetrics = (index: number): ?{length: number, offset: number, index: number} => {
|
||||
_getFrameMetrics = (
|
||||
index: number,
|
||||
): ?{length: number, offset: number, index: number, inLayout?: boolean} => {
|
||||
const {data, getItem, getItemCount, getItemLayout, keyExtractor} = this.props;
|
||||
invariant(getItemCount(data) > index, 'Tried to get frame for out of range index ' + index);
|
||||
const item = getItem(data, index);
|
||||
@@ -767,7 +788,9 @@ class CellRenderer extends React.Component {
|
||||
const {renderItem, getItemLayout} = parentProps;
|
||||
invariant(renderItem, 'no renderItem!');
|
||||
const element = renderItem({item, index});
|
||||
if (getItemLayout && !parentProps.debug) {
|
||||
if (getItemLayout &&
|
||||
!parentProps.debug &&
|
||||
!FillRateHelper.enabled()) {
|
||||
return element;
|
||||
}
|
||||
// NOTE: that when this is a sticky header, `onLayout` will get automatically extracted and
|
||||
|
||||
Reference in New Issue
Block a user