Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Calling worklets from within a worklet doesn't work #5576

Closed
mrousavy opened this issue Jan 11, 2024 · 5 comments
Closed

Calling worklets from within a worklet doesn't work #5576

mrousavy opened this issue Jan 11, 2024 · 5 comments
Labels
Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@mrousavy
Copy link
Contributor

mrousavy commented Jan 11, 2024

Description

Calling a nested worklet (on another runtime) from within an existing worklet does not work, because the nested worklet apparently doesn't compile properly.

This code breaks:

const context1 = createWorkletRuntime('context1')
const context2 = createWorkletRuntime('context2')

const runAsync = runOnRuntime(context2, (func: () => void) => {
  'worklet'
  try {
    // Call long-running function on a background context
    func()
  } catch (e) {
    // Re-throw error on JS Thread
    throwJSError(e)
  }
})

const runNormalWorklet = runOnRuntime(context1, () => {
  'worklet'
  
  console.log('running from context1!')
  runAsync(() => {
    'worklet'
    console.log('running from context2!')
  })
})

runNormalWorklet()

Because the inlined function is not properly converted to a Worklet by the babel plugin:

ReanimatedError: [Reanimated] Tried to synchronously call a non-worklet function on the UI thread.
See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-synchronously-call-a-non-worklet-function-on-the-ui-thread` for more details., js engine: reanimated

When I lift out the worklet function from the worklet itself, it also doesn't work (with the same error as above):

+ const fn = () => {
+   'worklet'
+   console.log('running from context2')
+ }

 const runNormalWorklet = runOnRuntime(context1, () => {
   'worklet'
  
   console.log('running from context1!')
-  runAsync(() => {
-    'worklet'
-   console.log('running from context2!')
-  })
+  runAsync(fn)
 })

When calling runOnRuntime directly from the worklet in context1 (so without the runAsync roundtrip):

 const runNormalWorklet = runOnRuntime(context1, () => {
   'worklet'
  
   console.log('running from context1!')
-  runAsync(() => {
-    'worklet'
-   console.log('running from context2!')
-  })
+  runOnRuntime(context2, () => {
+    'worklet';
+    console.log('running from context2!');
+  })();
 })

...it completely crashes the app with this error:

image

Steps to reproduce

  1. Run code above to verify error

Snack or a link to a repository

https://github.com/mrousavy/react-native-reanimated/tree/repro/nested-worklets

Reanimated version

3.6.0

React Native version

0.73.1

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

React Native

Architecture

Paper (Old Architecture)

Build type

Debug app & dev bundle

Device

iOS simulator

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided labels Jan 11, 2024
@tjzel
Copy link
Collaborator

tjzel commented Jan 12, 2024

Hi @mrousavy. Do you have processNestedWorklets enabled in Reanimated Babel plugin?

@mrousavy
Copy link
Contributor Author

Hey - no I did not. I wasn't aware that this was behind a feature flag - is there any reason this is not enabled by default? I can offer help testing in a production app to see if that breaks anything.

@tjzel
Copy link
Collaborator

tjzel commented Jan 18, 2024

I've noticed some issues when using this keyword in nested worklets - it seems to be troublesome because Hermes currently doesn't support variable scoping. I don't really recall any uses of worklets that use this though so it's not really a blocker. We just haven't got much feedback on that so that's why we are hesitant with enabling it by default.

Testing in production app would be greatly appreciated, thank you!

@mrousavy
Copy link
Contributor Author

I mean why would anyone use this in a worklet? They're not instance based anyways and you cannot use classes in there, right?

@tjzel
Copy link
Collaborator

tjzel commented Jan 18, 2024

Yes, you cannot use classes there (Hermes pls), but they actually sometimes have a context with this, although you shouldn't rely on it.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided
Projects
None yet
Development

No branches or pull requests

2 participants