Why is it stuck
Although the Main thread of most ReactNative applications does keep 60FPS, why sometimes we still feel stuck,
In fact, this is because of the asynchronous communication between the JS thread and the Main thread, resulting in the user’s gestures not being feedback in time, so our article mainly talks about the performance optimization of ReactNative applications
Animation
JS frame animation
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/Libraries/Animated/animations/TimingAnimation.js#L126 |
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/React/CoreModules/RCTTiming.mm#L296 |
requestAnimationFrame is a timer function exposed by Native to JS. Every time the timer triggers a frame animation, the JS thread will recalculate the layout, and then switch to the Main thread to update these layouts. Ordinary JS animations are generally very stuck, because the frame timer is in the The thread may be very busy, the communication between threads may take time to wait, and the frame timer keeps making the main thread refresh the interface while the main thread may also be busy, so it is very common to encounter performance problems when using JS animation. What are the common solutions?
Native frame animation useNativeDriver
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m#L429 |
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m#L85 |
useNativeDriver, what is the actual function of this property? Looking the source code of ReactNative or react-native-reanimated, we can see that a variable value is bound in the native side, and a CADisplayLink is created. This frame timer is to change the bound variable value frame by frame, and then refresh the corresponding interface after the value is changed in the main thread, which will not involve JS thread communication, so most of the cases can help solve our performance problems, but there are sometimes we will still encounter animation performance problems that cannot be solved by useNativeDriver, Because the frame loss of CADisplayLink frame animation, how do we deal with this situation?
Native layout animation LayoutAnimation
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/React/Modules/RCTLayoutAnimation.m#L107-L127 |
LayoutAnimation can solve this problem, and why, we can find out by looking at the source code, because LayoutAnimation does not start the native frame animation, but the native UIView animation that comes with iOS, because the animation of iOS is a separate process for animation. This animation is a process animation and has nothing to do with threads, so even if the Main thread is too busy, the animation process will directly complete the animation. Similarly, the animation framework of android may also have its own optimization, such as hardware acceleration, etc.
Gesture Events
JS Gesture Events
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/React/Base/RCTTouchHandler.m#L186 |
Ordinary JS gesture processing is generally very slow, because the main thread receives the gesture, sends the gesture to the JS thread, and then executes the JS method. The Main thread receives the interface properties that should be updated, which involves two cross-threads Transferring data, among them, it is absolutely possible to wait for communication. How do we usually solve it?
Native Gesture Events
Similarly, the useNativeDriver mentioned above, we also have an event called nativeEvent, usually, them are used together, the native gesture will send a global notification, the animation framework will listen to this event, and then directly update the value of the animation binding As well as refreshing the interface directly on the main thread, we also don’t need asynchronous JS thread communication, so react-native-gesture-handler really solves a lot of performance problems
1 | // https://github.com/facebook/react-native/blob/26b2bb5343f92672ed4e8f42c6f839e903124b06/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm#L76 |
Affiliated
I’m hublot, sharing some of my thoughts, I’m too busy with work, it’s inevitable that there will be negligence, please forgive me