1 | 'use strict';
|
2 | import NativeReanimatedModule from './NativeReanimated';
|
3 | import { isJest, shouldBeUseWeb } from './PlatformChecker';
|
4 | import type { WorkletFunction } from './commonTypes';
|
5 | import {
|
6 | makeShareableCloneOnUIRecursive,
|
7 | makeShareableCloneRecursive,
|
8 | } from './shareables';
|
9 | import { isWorkletFunction } from './commonTypes';
|
10 |
|
11 | const IS_JEST = isJest();
|
12 | const SHOULD_BE_USE_WEB = shouldBeUseWeb();
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | let _runOnUIQueue: Array<[WorkletFunction<unknown[], unknown>, unknown[]]> = [];
|
18 |
|
19 | export function setupMicrotasks() {
|
20 | 'worklet';
|
21 |
|
22 | let microtasksQueue: Array<() => void> = [];
|
23 | let isExecutingMicrotasksQueue = false;
|
24 | global.queueMicrotask = (callback: () => void) => {
|
25 | microtasksQueue.push(callback);
|
26 | };
|
27 |
|
28 | global.__callMicrotasks = () => {
|
29 | if (isExecutingMicrotasksQueue) {
|
30 | return;
|
31 | }
|
32 | try {
|
33 | isExecutingMicrotasksQueue = true;
|
34 | for (let index = 0; index < microtasksQueue.length; index += 1) {
|
35 |
|
36 | microtasksQueue[index]();
|
37 | }
|
38 | microtasksQueue = [];
|
39 | global._maybeFlushUIUpdatesQueue();
|
40 | } finally {
|
41 | isExecutingMicrotasksQueue = false;
|
42 | }
|
43 | };
|
44 | }
|
45 |
|
46 | function callMicrotasksOnUIThread() {
|
47 | 'worklet';
|
48 | global.__callMicrotasks();
|
49 | }
|
50 |
|
51 | export const callMicrotasks = SHOULD_BE_USE_WEB
|
52 | ? () => {
|
53 |
|
54 | }
|
55 | : callMicrotasksOnUIThread;
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | export function runOnUI<Args extends unknown[], ReturnValue>(
|
71 | worklet: (...args: Args) => ReturnValue
|
72 | ): (...args: Args) => void;
|
73 |
|
74 | export function runOnUI<Args extends unknown[], ReturnValue>(
|
75 | worklet: WorkletFunction<Args, ReturnValue>
|
76 | ): (...args: Args) => void {
|
77 | 'worklet';
|
78 | if (__DEV__ && !SHOULD_BE_USE_WEB && _WORKLET) {
|
79 | throw new Error(
|
80 | '[Reanimated] `runOnUI` cannot be called on the UI runtime. Please call the function synchronously or use `queueMicrotask` or `requestAnimationFrame` instead.'
|
81 | );
|
82 | }
|
83 | if (__DEV__ && !SHOULD_BE_USE_WEB && !isWorkletFunction(worklet)) {
|
84 | throw new Error('[Reanimated] `runOnUI` can only be used on worklets.');
|
85 | }
|
86 | return (...args) => {
|
87 | if (IS_JEST) {
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | NativeReanimatedModule.scheduleOnUI(
|
98 | makeShareableCloneRecursive(() => {
|
99 | 'worklet';
|
100 | worklet(...args);
|
101 | })
|
102 | );
|
103 | return;
|
104 | }
|
105 | if (__DEV__) {
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | makeShareableCloneRecursive(worklet);
|
112 | makeShareableCloneRecursive(args);
|
113 | }
|
114 | _runOnUIQueue.push([worklet as WorkletFunction, args]);
|
115 | if (_runOnUIQueue.length === 1) {
|
116 | queueMicrotask(() => {
|
117 | const queue = _runOnUIQueue;
|
118 | _runOnUIQueue = [];
|
119 | NativeReanimatedModule.scheduleOnUI(
|
120 | makeShareableCloneRecursive(() => {
|
121 | 'worklet';
|
122 |
|
123 | queue.forEach(([worklet, args]) => {
|
124 | worklet(...args);
|
125 | });
|
126 | callMicrotasks();
|
127 | })
|
128 | );
|
129 | });
|
130 | }
|
131 | };
|
132 | }
|
133 |
|
134 |
|
135 | export function executeOnUIRuntimeSync<Args extends unknown[], ReturnValue>(
|
136 | worklet: (...args: Args) => ReturnValue
|
137 | ): (...args: Args) => ReturnValue;
|
138 |
|
139 | export function executeOnUIRuntimeSync<Args extends unknown[], ReturnValue>(
|
140 | worklet: WorkletFunction<Args, ReturnValue>
|
141 | ): (...args: Args) => ReturnValue {
|
142 | return (...args) => {
|
143 | return NativeReanimatedModule.executeOnUIRuntimeSync(
|
144 | makeShareableCloneRecursive(() => {
|
145 | 'worklet';
|
146 | const result = worklet(...args);
|
147 | return makeShareableCloneOnUIRecursive(result);
|
148 | })
|
149 | );
|
150 | };
|
151 | }
|
152 |
|
153 |
|
154 | export function runOnUIImmediately<Args extends unknown[], ReturnValue>(
|
155 | worklet: (...args: Args) => ReturnValue
|
156 | ): WorkletFunction<Args, ReturnValue>;
|
157 |
|
158 |
|
159 |
|
160 | export function runOnUIImmediately<Args extends unknown[], ReturnValue>(
|
161 | worklet: WorkletFunction<Args, ReturnValue>
|
162 | ): (...args: Args) => void {
|
163 | 'worklet';
|
164 | if (__DEV__ && !SHOULD_BE_USE_WEB && _WORKLET) {
|
165 | throw new Error(
|
166 | '[Reanimated] `runOnUIImmediately` cannot be called on the UI runtime. Please call the function synchronously or use `queueMicrotask` or `requestAnimationFrame` instead.'
|
167 | );
|
168 | }
|
169 | if (__DEV__ && !SHOULD_BE_USE_WEB && !isWorkletFunction(worklet)) {
|
170 | throw new Error(
|
171 | '[Reanimated] `runOnUIImmediately` can only be used on worklets.'
|
172 | );
|
173 | }
|
174 | return (...args) => {
|
175 | NativeReanimatedModule.scheduleOnUI(
|
176 | makeShareableCloneRecursive(() => {
|
177 | 'worklet';
|
178 | worklet(...args);
|
179 | })
|
180 | );
|
181 | };
|
182 | }
|
183 |
|
184 | type ReleaseRemoteFunction<Args extends unknown[], ReturnValue> = {
|
185 | (...args: Args): ReturnValue;
|
186 | };
|
187 |
|
188 | type DevRemoteFunction<Args extends unknown[], ReturnValue> = {
|
189 | __remoteFunction: (...args: Args) => ReturnValue;
|
190 | };
|
191 |
|
192 | type RemoteFunction<Args extends unknown[], ReturnValue> =
|
193 | | ReleaseRemoteFunction<Args, ReturnValue>
|
194 | | DevRemoteFunction<Args, ReturnValue>;
|
195 |
|
196 | function runWorkletOnJS<Args extends unknown[], ReturnValue>(
|
197 | worklet: WorkletFunction<Args, ReturnValue>,
|
198 | ...args: Args
|
199 | ): void {
|
200 |
|
201 | worklet(...args);
|
202 | }
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 | export function runOnJS<Args extends unknown[], ReturnValue>(
|
213 | fun:
|
214 | | ((...args: Args) => ReturnValue)
|
215 | | RemoteFunction<Args, ReturnValue>
|
216 | | WorkletFunction<Args, ReturnValue>
|
217 | ): (...args: Args) => void {
|
218 | 'worklet';
|
219 | type FunDevRemote = Extract<typeof fun, DevRemoteFunction<Args, ReturnValue>>;
|
220 | if (SHOULD_BE_USE_WEB || !_WORKLET) {
|
221 |
|
222 | return (...args) =>
|
223 | queueMicrotask(
|
224 | args.length
|
225 | ? () => (fun as (...args: Args) => ReturnValue)(...args)
|
226 | : (fun as () => ReturnValue)
|
227 | );
|
228 | }
|
229 | if (isWorkletFunction<Args, ReturnValue>(fun)) {
|
230 | // If `fun` is a worklet, we schedule a call of a remote function `runWorkletOnJS`
|
231 | // and pass the worklet as a first argument followed by original arguments.
|
232 |
|
233 | return (...args) =>
|
234 | runOnJS(runWorkletOnJS<Args, ReturnValue>)(
|
235 | fun as WorkletFunction<Args, ReturnValue>,
|
236 | ...args
|
237 | );
|
238 | }
|
239 | if ((fun as FunDevRemote).__remoteFunction) {
|
240 |
|
241 |
|
242 |
|
243 |
|
244 | fun = (fun as FunDevRemote).__remoteFunction;
|
245 | }
|
246 | return (...args) => {
|
247 | global._scheduleOnJS(
|
248 | fun as
|
249 | | ((...args: Args) => ReturnValue)
|
250 | | WorkletFunction<Args, ReturnValue>,
|
251 | args.length > 0
|
252 | ? // TODO TYPESCRIPT this cast is terrible but will be fixed
|
253 | (makeShareableCloneOnUIRecursive(args) as unknown as unknown[])
|
254 | : undefined
|
255 | );
|
256 | };
|
257 | }
|
258 |
|
\ | No newline at end of file |