mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Animated: Enqueue Completion Callbacks in Microtask (#46714)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46714 Sets up a feature flag to experiment with scheduling `Animation` completion callbacks in a microtask instead of executing them synchronously. (The completion callback is the callback passed into `animation.start(<callback>)`). There are currently 4 potential scheduling behaviors of the animation completion callback: - Synchronously when `start()` is invoked, for spring and timing animations that immediately complete (e.g. no delays and not native driver). - Synchronously when `stop()` is invoked, if the animation has not yet completed. - Synchronously during the layout effect phase, or commit phase (if the `useInsertionEffectsForAnimations` feature flag is enabled), if the animation has not yet completed. - Asynchronously when the animation completes (e.g. non-zero delay or when the native driver is employed). The wide number of variables and the timing-dependent nature of these variables means that the behavior of the completion callback is very non-deterministic. Imperically, we have also found that most codebases using `useNativeDriver` mostly have completion callbacks executed asynchronously. However, this leads to surprising problems where the callback causes unpredictable behavior when it is called synchronously (e.g. when the animating component is unmounted *during* the animation). Changelog: [Internal] Reviewed By: javache Differential Revision: D63573322 fbshipit-source-id: 16c48be78c9ac65a64021249fad10f7265737c44
This commit is contained in:
committed by
Facebook GitHub Bot
parent
11bf3a32e1
commit
de927e6138
@@ -165,7 +165,11 @@ export default class Animation {
|
||||
const callback = this.#onEnd;
|
||||
if (callback != null) {
|
||||
this.#onEnd = null;
|
||||
callback(result);
|
||||
if (ReactNativeFeatureFlags.scheduleAnimatedEndCallbackInMicrotask()) {
|
||||
queueMicrotask(() => callback(result));
|
||||
} else {
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,6 +541,15 @@ const definitions: FeatureFlagDefinitions = {
|
||||
purpose: 'release',
|
||||
},
|
||||
},
|
||||
scheduleAnimatedEndCallbackInMicrotask: {
|
||||
defaultValue: false,
|
||||
metadata: {
|
||||
dateAdded: '2024-09-27',
|
||||
description:
|
||||
'Changes the completion callback supplied via `Animation#start` to be scheduled in a microtask instead of synchronously executed.',
|
||||
purpose: 'experimentation',
|
||||
},
|
||||
},
|
||||
shouldSkipStateUpdatesForLoopingAnimations: {
|
||||
defaultValue: false,
|
||||
metadata: {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<eae8bf8e1f529a034a65377353cda539>>
|
||||
* @generated SignedSource<<36900baefd540f0fbb5920e9001b969c>>
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@ export type ReactNativeFeatureFlagsJsOnly = {
|
||||
enableAnimatedPropsMemo: Getter<boolean>,
|
||||
enableOptimisedVirtualizedCells: Getter<boolean>,
|
||||
isLayoutAnimationEnabled: Getter<boolean>,
|
||||
scheduleAnimatedEndCallbackInMicrotask: Getter<boolean>,
|
||||
shouldSkipStateUpdatesForLoopingAnimations: Getter<boolean>,
|
||||
shouldUseAnimatedObjectForTransform: Getter<boolean>,
|
||||
shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter<boolean>,
|
||||
@@ -146,6 +147,11 @@ export const enableOptimisedVirtualizedCells: Getter<boolean> = createJavaScript
|
||||
*/
|
||||
export const isLayoutAnimationEnabled: Getter<boolean> = createJavaScriptFlagGetter('isLayoutAnimationEnabled', true);
|
||||
|
||||
/**
|
||||
* Changes the completion callback supplied via `Animation#start` to be scheduled in a microtask instead of synchronously executed.
|
||||
*/
|
||||
export const scheduleAnimatedEndCallbackInMicrotask: Getter<boolean> = createJavaScriptFlagGetter('scheduleAnimatedEndCallbackInMicrotask', false);
|
||||
|
||||
/**
|
||||
* If the animation is within Animated.loop, we do not send state updates to React.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user