margelo / react-native-worklets-core

🧵 A library to run JS functions ("Worklets") on separate Threads
https://margelo.io
MIT License
543 stars 37 forks source link

In callInContext the function parameter is not a valid worklet and cannot be called between contexts or from/to JS from/to a context. #125

Open Acetyld opened 11 months ago

Acetyld commented 11 months ago

While using:

function RealApp() {
  const fibonacci = (num: number): number => {
    'worklet';
    if (num <= 1) return 1;
    return fibonacci(num - 1) + fibonacci(num - 2);
  };

  const worklet = Worklets.createRunInContextFn(fibonacci);
  worklet(50).then(result => {
    console.log(`Fibonacci of 50 is ${result}`);
  });
}

I get:

In callInContext the function parameter is not a valid worklet and cannot be called between contexts or from/to JS from/to a context.

Running:

Expo: 49

Babel:
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      'nativewind/babel',
      'module:react-native-dotenv',
      'react-native-worklets-core/plugin',
      'react-native-reanimated/plugin',
      ['@babel/plugin-transform-flow-strip-types', { loose: true }],
      ['@babel/plugin-proposal-private-methods', { loose: true }],
    ],
  };
};

I did rebuild, prebuild, clean cache, clean pods, removed node modules reinstalled etc..

mrousavy commented 11 months ago

Is this because of recursion? Does it work if you refactor your code to use simple for loops instead of recursively calling fibonacci?

omermizr commented 11 months ago

Same thing happening to me, with the simplest worklet possible - just immediately returning a string

matis-dk commented 11 months ago

Happening to me as well. Running on Expo 49, and build with EAS. When starting the Expo dev server:

 LOG  Loading react-native-worklets-core...
 LOG  Worklets loaded successfully

Is this package compatible with Expo ?

chrfalch commented 11 months ago

The problem with the fibionacci example is that when the using recursion like you do - the function is not available as a worklet at the point of initialisation and will therefore be undefined in the context of the workletized fibionacci function. Reanimated gives the same error:

const fibonacci = (num: number): number => {
    "worklet";
    if (num <= 1) return 1;
    return fibonacci(num - 1) + fibonacci(num - 2);
};

runOnUI(fibonacci)(100);

Results in:

ERROR  ReanimatedError: undefined is not a function, js engine: reanimated

You can look at the transpiled code for the worklet to see that this is failing at the declaration level:

console.log("Closure:", fibonacci.__closure);

Results in:

closure: {"fibonacci": undefined}

Meaning that the worklet is not yet created when the plugin transforms its closure.

mrousavy commented 11 months ago

Makes complete sense, recursion doesn't need to be supported imo.

lgspacil commented 10 months ago

Any update on this? I am experiencing the same error. For example my code is:

const test = (num: number): number => {
    'worklet'
    return num * 2;
};

useEffect(() => {
    const run = async () => {
        try {
            const worklet = Worklets.createRunInContextFn(test);
            const result = await worklet(50);
            console.log(`result is ${result}`);
        } catch (e) {
            console.log(e);
        }
    };

    run();
}, []);

When I look at the logs I see:

Loading react-native-worklets-core... Worklets loaded successfully [Error: In callInContext the function parameter is not a valid worklet and cannot be called between contexts or from/to JS from/to a context.]

nikhilyadavvvv commented 7 months ago

const worklet = useWorklet( 'default', () => { 'worklet'; console.log('hello from worklet!'); }, [], ); useEffect(() => { worklet(); }, []);

Even this doesn't work. How am i suppose to use this lib

Acetyld commented 7 months ago

I don't think this library is ment or at a point for public usage to easily run stuff on a seperate worker.

margelo is one of the goats of RN (imo :P) but don't know what his plans are for this library, i hope someday we have a library like https://github.com/joltup/react-native-threads or the old multi-tread from margelo so we can easily do extensive stuff on a seperate thread ;p

mrousavy commented 7 months ago

I don't think this library is ment or at a point for public usage to easily run stuff on a seperate worker.

It is - but there is not a lot of real world cases for when you would use that- heavy lifting should be done on the native side, not on JS.

margelo is one of the goats of RN (imo :P)

Thank you! ❤️

but don't know what his plans are for this library, i hope someday we have a library like https://github.com/joltup/react-native-threads or the old multi-tread from margelo so we can easily do extensive stuff on a seperate thread ;p

Worklets is a new and improved version of my old multithreading library. Worklets can be used to run stuff on a separate Thread, and the example app here demonstrates how to do that.

VisionCamera V3 also uses this for Frame Processors, and this is being used in production by many apps.

levepic commented 7 months ago

Im also upto using it in production but there is the memory leak issue (#137 , #129 ). Am I missing something? Is there a way to avoid that? Obviously I need to return some data to javascript (when a face is recognized etc) so somehow I need to call a JS function or set state from the worklet. Is there a way to do that without the memory leak bug? Without calling JS what would you use the worklet for if it cannot send any information the the js thread.

ellora-virtue commented 7 months ago

Similar to @lgspacil and @nikhilyadavvvv, I am trying to implement a very simple example from the usage doc and gettingError: In callInContext the function parameter is not a valid worklet and cannot be called between contexts or from/to JS from/to a context. in my console.

This happens after the logs Loading react-native-worklets-core... and Worklets loaded successfully.

I am using it in a React component, like so:

const worklet = useWorklet(
    'default',
    () => {
      'worklet';

      console.log('hello from worklet!');
    },
    [],
  );

 worklet();

@mrousavy are we missing something from this usage example?

chrfalch commented 7 months ago

Did you install the plugin as described in the installation instructions? It is need so that the Javascript function is decorated with information necessary to make it runnable on another thread.

ellora-virtue commented 7 months ago

@chrfalch yes I did 🙂 provided you're talking about this step:

  1. Add the babel plugin to your babel.config.js:
    module.exports = {
    plugins: [
    ["react-native-worklets-core/plugin"],
    // ...
    ],
    // ...
    };
ellora-virtue commented 7 months ago

My issue above looks to have been caused by the fact that our repo was using an older version of react-native-reanimated (^2.14.1). Upgrading this to the latest version (^3.7.2) has fixed this for me - hope this helps someone else too!

lgspacil commented 6 months ago

@ellora-virtue Did you have a way to return a value from the worklet?