mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
improve interpolation performance with big input range (#33598)
Summary: This drastically improves `Animated.interpolate` performance when `inputRange` has a considerable amount of elements (~100 in my tests). For instance in `ActivityIndicator` inside `react-native-paper`, the input has 144 elements https://github.com/callstack/react-native-paper/blob/main/src/components/ActivityIndicator.tsx#L170. `react-native-elements` has 9k stars, so I'm assuming this is widely used. ### Cause The reason for the performance drop is that if we assume `n` to be the size of the range, calculating `'inputRange must be monotonically non-decreasing ' + arr` essentially calculates `arr.toString()` which has O(n) complexity. Since it is recalculated in a for loop, we end up with `checkValidInputRange` having a O(n²) complexity. Which means ~10k operations if the array has a size close to 100. ## Changelog [General] [Fixed] - Fix performance issue on Animated.interpolate with big input range Pull Request resolved: https://github.com/facebook/react-native/pull/33598 Test Plan: [Here's a repo](https://github.com/Almouro/AnimatedInterpolationRepro) reproducing the issue. The branch `fix` includes the fix. Clicking `Interpolate` runs: ```js new Animated.Value(0).interpolate({ inputRange: Array(144) .fill() .map((_, i) => 1 / (i + 1)) .reverse(), outputRange: Array(144) .fill() .map((_, i) => 1 / (i + 1)) ``` Here's a comparison of JS thread perf before the fix and after the fix: - on a Samsung J3 2017 (lower end) - using Flipper and https://github.com/bamlab/react-native-performance) - ` __DEV__` mode deactivated - clicking the button and waiting 15s | Before | After | |----------|:-------------:| |  | | The error still throws if `inputRange` is incorrect: <img width="517" alt="image" src="https://user-images.githubusercontent.com/4534323/162439219-6ce120ae-98e5-496b-899a-492978689d6d.png"> However if `__DEV__` mode is deactivated, no error is thrown Reviewed By: yungsters Differential Revision: D35507441 Pulled By: javache fbshipit-source-id: 36ac49422f7a42d247130c42d12248b2be1232c6
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e14736589e
commit
f503b21203
@@ -46,20 +46,23 @@ function createInterpolation(
|
||||
}
|
||||
|
||||
const outputRange: Array<number> = (config.outputRange: any);
|
||||
checkInfiniteRange('outputRange', outputRange);
|
||||
|
||||
const inputRange = config.inputRange;
|
||||
checkInfiniteRange('inputRange', inputRange);
|
||||
checkValidInputRange(inputRange);
|
||||
|
||||
invariant(
|
||||
inputRange.length === outputRange.length,
|
||||
'inputRange (' +
|
||||
inputRange.length +
|
||||
') and outputRange (' +
|
||||
outputRange.length +
|
||||
') must have the same length',
|
||||
);
|
||||
if (__DEV__) {
|
||||
checkInfiniteRange('outputRange', outputRange);
|
||||
checkInfiniteRange('inputRange', inputRange);
|
||||
checkValidInputRange(inputRange);
|
||||
|
||||
invariant(
|
||||
inputRange.length === outputRange.length,
|
||||
'inputRange (' +
|
||||
inputRange.length +
|
||||
') and outputRange (' +
|
||||
outputRange.length +
|
||||
') must have the same length',
|
||||
);
|
||||
}
|
||||
|
||||
const easing = config.easing || linear;
|
||||
|
||||
@@ -276,16 +279,10 @@ function findRange(input: number, inputRange: $ReadOnlyArray<number>) {
|
||||
|
||||
function checkValidInputRange(arr: $ReadOnlyArray<number>) {
|
||||
invariant(arr.length >= 2, 'inputRange must have at least 2 elements');
|
||||
const message =
|
||||
'inputRange must be monotonically non-decreasing ' + String(arr);
|
||||
for (let i = 1; i < arr.length; ++i) {
|
||||
invariant(
|
||||
arr[i] >= arr[i - 1],
|
||||
/* $FlowFixMe[incompatible-type] (>=0.13.0) - In the addition expression
|
||||
* below this comment, one or both of the operands may be something that
|
||||
* doesn't cleanly convert to a string, like undefined, null, and object,
|
||||
* etc. If you really mean this implicit string conversion, you can do
|
||||
* something like String(myThing) */
|
||||
'inputRange must be monotonically non-decreasing ' + arr,
|
||||
);
|
||||
invariant(arr[i] >= arr[i - 1], message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user