Skip to content

Commit

Permalink
fix: move requestAnimationFrame back to Reanimated (#6991)
Browse files Browse the repository at this point in the history
## Summary

I introduced a regression in #6973 by moving JS implementation of
`requestAnimationFrame` to Worklets. Native version of
`requestAnimationFrame` is injected in Reanimated's
`UIRuntimeDecorator.cpp` so `requestAnimationFrame` must be overwritten
in Reanimated, not in Worklets.

Since all the native implementation is in Reanimated and it would be a
hard task to extract it right now, I decided to keep it for the time
being unless we decide where it should land eventually.

## Test plan

The only difference is the lack of batching with my regression
introduced. You can `console.log(currentCallbacks.length)` to see that
the batching is restored.
  • Loading branch information
tjzel authored Feb 6, 2025
1 parent 455d94a commit 753464b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { getShadowNodeWrapperFromRef } from '../fabricUtils';
import { checkCppVersion } from '../platform-specific/checkCppVersion';
import { jsVersion } from '../platform-specific/jsVersion';
import { isFabric, shouldBeUseWeb } from '../PlatformChecker';
import { setupRequestAnimationFrame } from '../requestAnimationFrame';
import { ReanimatedTurboModule } from '../specs';
import type {
IWorkletsModule,
Expand Down Expand Up @@ -81,7 +82,11 @@ See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooti
checkCppVersion();
}
this.#reanimatedModuleProxy = global.__reanimatedModuleProxy;
executeOnUIRuntimeSync(registerReanimatedError);
executeOnUIRuntimeSync(function initializeUI() {
'worklet';
registerReanimatedError();
setupRequestAnimationFrame();
})();
}

registerSensor(
Expand Down
4 changes: 3 additions & 1 deletion packages/react-native-reanimated/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { createCustomError, registerCustomError } from './WorkletsResolver';

export const ReanimatedError = createCustomError('Reanimated');

const ReanimatedErrorConstructor = ReanimatedError;

export function registerReanimatedError() {
'worklet';
registerCustomError(ReanimatedError, 'Reanimated');
registerCustomError(ReanimatedErrorConstructor, 'Reanimated');
}
41 changes: 41 additions & 0 deletions packages/react-native-reanimated/src/requestAnimationFrame.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

import { callMicrotasks } from './WorkletsResolver';

export function setupRequestAnimationFrame() {
'worklet';

// Jest mocks requestAnimationFrame API and it does not like if that mock gets overridden
// so we avoid doing requestAnimationFrame batching in Jest environment.
const nativeRequestAnimationFrame = global.requestAnimationFrame;

let animationFrameCallbacks: Array<(timestamp: number) => void> = [];
let flushRequested = false;

global.__flushAnimationFrame = (frameTimestamp: number) => {
const currentCallbacks = animationFrameCallbacks;
animationFrameCallbacks = [];
currentCallbacks.forEach((f) => f(frameTimestamp));
callMicrotasks();
};

global.requestAnimationFrame = (
callback: (timestamp: number) => void
): number => {
animationFrameCallbacks.push(callback);
if (!flushRequested) {
flushRequested = true;
nativeRequestAnimationFrame((timestamp) => {
flushRequested = false;
global.__frameTimestamp = timestamp;
global.__flushAnimationFrame(timestamp);
global.__frameTimestamp = undefined;
});
}
// Reanimated currently does not support cancelling callbacks requested with
// requestAnimationFrame. We return -1 as identifier which isn't in line
// with the spec but it should give users better clue in case they actually
// attempt to store the value returned from rAF and use it for cancelling.
return -1;
};
}
46 changes: 1 addition & 45 deletions packages/react-native-worklets/src/worklets/initializers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@ import {
isWeb,
shouldBeUseWeb,
} from './PlatformChecker';
import {
callMicrotasks,
executeOnUIRuntimeSync,
runOnJS,
setupMicrotasks,
} from './threads';
import { executeOnUIRuntimeSync, runOnJS, setupMicrotasks } from './threads';
import { registerWorkletsError, WorkletsError } from './WorkletsError';
import type { IWorkletsModule } from './WorkletsModule';

Expand Down Expand Up @@ -148,44 +143,6 @@ export function setupConsole() {
}
}

function setupRequestAnimationFrame() {
'worklet';

// Jest mocks requestAnimationFrame API and it does not like if that mock gets overridden
// so we avoid doing requestAnimationFrame batching in Jest environment.
const nativeRequestAnimationFrame = global.requestAnimationFrame;

let animationFrameCallbacks: Array<(timestamp: number) => void> = [];
let flushRequested = false;

global.__flushAnimationFrame = (frameTimestamp: number) => {
const currentCallbacks = animationFrameCallbacks;
animationFrameCallbacks = [];
currentCallbacks.forEach((f) => f(frameTimestamp));
callMicrotasks();
};

global.requestAnimationFrame = (
callback: (timestamp: number) => void
): number => {
animationFrameCallbacks.push(callback);
if (!flushRequested) {
flushRequested = true;
nativeRequestAnimationFrame((timestamp) => {
flushRequested = false;
global.__frameTimestamp = timestamp;
global.__flushAnimationFrame(timestamp);
global.__frameTimestamp = undefined;
});
}
// Reanimated currently does not support cancelling callbacks requested with
// requestAnimationFrame. We return -1 as identifier which isn't in line
// with the spec but it should give users better clue in case they actually
// attempt to store the value returned from rAF and use it for cancelling.
return -1;
};
}

export function initializeUIRuntime(WorkletsModule: IWorkletsModule) {
if (isWeb()) {
return;
Expand All @@ -211,7 +168,6 @@ export function initializeUIRuntime(WorkletsModule: IWorkletsModule) {
setupCallGuard();
setupConsole();
setupMicrotasks();
setupRequestAnimationFrame();
})();
}
}

0 comments on commit 753464b

Please sign in to comment.