Skip to content

Commit ea8e42b

Browse files
zeyapfacebook-github-bot
authored andcommitted
Flush NativeAnimated batch via microtask instead of set/clearImmediate (#57209)
Summary: ## Changelog: [Internal] - Flush NativeAnimated batch via microtask instead of set/clearImmediate We used `setImmediate` to schedule the operations in order to use microtasks queue (given the immediate shim used in RN). But jest tests treat setImmediate callback as macrotask like setTimeout (which is browser-aligned behavior). This makes it difficult to test the change introduced by featureflag `animatedShouldDebounceQueueFlush` and `cxxNativeAnimatedEnabled` Reviewed By: cipolleschi Differential Revision: D108640934
1 parent fc7dc74 commit ea8e42b

3 files changed

Lines changed: 208 additions & 27 deletions

File tree

packages/react-native/src/private/animated/NativeAnimatedHelper.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {EventSubscription} from '../../../Libraries/vendor/emitter/EventEmi
2323

2424
import NativeAnimatedNonTurboModule from '../../../Libraries/Animated/NativeAnimatedModule';
2525
import NativeAnimatedTurboModule from '../../../Libraries/Animated/NativeAnimatedTurboModule';
26+
import queueMicrotask from '../../../Libraries/Core/Timers/queueMicrotask';
2627
import NativeEventEmitter from '../../../Libraries/EventEmitter/NativeEventEmitter';
2728
import RCTDeviceEventEmitter from '../../../Libraries/EventEmitter/RCTDeviceEventEmitter';
2829
import Platform from '../../../Libraries/Utilities/Platform';
@@ -57,7 +58,6 @@ const isSingleOpBatching =
5758
Platform.OS === 'android' &&
5859
NativeAnimatedModule?.queueAndExecuteBatchedOperations != null &&
5960
ReactNativeFeatureFlags.animatedShouldUseSingleOp();
60-
let flushQueueImmediate = null;
6161

6262
const eventListenerGetValueCallbacks: {
6363
[number]: (value: number) => void,
@@ -71,19 +71,18 @@ let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null;
7171
const shouldSignalBatch: boolean =
7272
ReactNativeFeatureFlags.cxxNativeAnimatedEnabled();
7373

74-
// Schedules `API.flushQueue` after the current batch, replacing any pending
75-
// flush. On device `setImmediate` is a microtask; under jest's fake timers it's
76-
// a fake-timer entry that only `runAllTimers` drains — not `await` or
77-
// `advanceTimersByTime` — so the deferred flush wouldn't run before a test's
78-
// assertions. Flush synchronously in tests instead.
74+
let flushQueueGeneration = 1;
7975
function scheduleQueueFlush(): void {
80-
clearImmediate(flushQueueImmediate);
81-
if (process.env.NODE_ENV === 'test') {
82-
// TODO: T275950736 - remove this path
76+
const generation = ++flushQueueGeneration;
77+
queueMicrotask(() => {
78+
if (generation !== flushQueueGeneration) {
79+
return;
80+
}
8381
API.flushQueue();
84-
} else {
85-
flushQueueImmediate = setImmediate(API.flushQueue);
86-
}
82+
});
83+
}
84+
function cancelQueueFlush(): void {
85+
flushQueueGeneration++;
8786
}
8887

8988
function createNativeOperations(): NonNullable<typeof NativeAnimatedModule> {
@@ -229,7 +228,6 @@ const API = {
229228
NativeAnimatedModule,
230229
'Native animated module is not available',
231230
);
232-
flushQueueImmediate = null;
233231

234232
if (singleOpQueue.length === 0) {
235233
return;
@@ -250,7 +248,6 @@ const API = {
250248
NativeAnimatedModule,
251249
'Native animated module is not available',
252250
);
253-
flushQueueImmediate = null;
254251

255252
if (queue.length === 0) {
256253
return;
@@ -310,11 +307,10 @@ const API = {
310307

311308
waitingForQueuedOperations.add(id);
312309
queueOperations = true;
313-
if (
314-
ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() &&
315-
flushQueueImmediate
316-
) {
317-
clearImmediate(flushQueueImmediate);
310+
// Entering explicit queue mode: drop any flush already scheduled so ops
311+
// accumulate until `disableQueue`.
312+
if (ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush()) {
313+
cancelQueueFlush();
318314
}
319315
},
320316
startAnimatingNode: (isSingleOpBatching

0 commit comments

Comments
 (0)