react-native-community / discussions-and-proposals

Discussions and proposals related to the main React Native project
https://reactnative.dev
1.66k stars 126 forks source link

JSI (JavaScript Interface) & JSC (JavaScript Core) Discussion #91

Closed kelset closed 2 years ago

kelset commented 5 years ago

What's the current status of JSI? Read here

Intro

With this issue I'd like to try and create a "one stop" for all the information available around the JavaScript Interface, the unified lightweight general purpose API for (theoretically) any JavaScript virtual machine.

Currently, the default Javascript Virtual Machine used by React Native is JavaScriptCore (JSC) - it is used in WebKit.

Terminology

TL;DR

From @axe-fb's blogpost, here's a temporary description of the JSI (please consider that this is not yet finalized, it may change in the future)

Instead of using the bridge for queuing messages, the new architecture allows us to directly "invoke" (think RPC) Java/ObjC methods. An analogy would be how we call DOM methods from JavaScript in the browser. For example, in the statement var el = document.createElement('div'); the variable el holds a reference not to a JavaScript object, but to an object that was possibly instantiated in C++. When JavaScript calls el.setAttribute('width', 100), we end up synchronously invoking the setWidth method in C++ that changes the actual width of that element. In React Native, we can similarly use the JavaScript interface to invoke methods on UI Views and Native Modules that are implemented in Java/ObjC.

Available Materials

At ReactConf 2018 @axe-fb did a talk about React Native's New Architecture, which also explains the 3 concepts above: JSI, Fabric, TurboModule.

Recently the JSC was upgraded for Android, you can check the commit here and the related issue in the main repo.

On twitter, @karanjthakkar did a thread detailing how he integrated the new JSC in the Skyscanner app.

In Q1 2019, @kelset wrote a high level explanation in a blogpost: https://formidable.com/blog/2019/jsi-jsc-part-2/ and did a talk about the whole rearchitecture in April 2019 at React Edinburgh.

Over on twitter, @ericlewis published a sample repo with @chrfalch to showcase how to use directly C++ in a RN app (thanks to the JSI): https://github.com/ericlewis/react-native-hostobject-demo

@kelset also did a more in-depth talk at React Advanced London in Oct 2019: youtube recording & slides.

@Jarred-Sumner published a quick benchmark difference between a lib and a reimplementation using JSI twitter.

Libraries implemented using JSI

Blogposts

Q&A

This is also a place for questions related to this effort and its direction.

ryantrem commented 4 years ago

@ryantrem Based on @tmikov's comment facebook/hermes#182 (comment) I think if you submitted a PR to enable these functions and tested that they work, there's no reason not to accept that.

Just to close the loop on this (array buffer support in JSCRuntime), the PR for this was completed and merged. Thanks @mhorowitz, @tmikov, and @shergin for helping make that happen!

acoates-ms commented 4 years ago

@vonovak Re: 2. No JSI by itself does not do anything to help this. - JSI is the basis for a UI re-architecture "fabric" which might be able to help here. But even then there is a thread boundary between the UI state and the JS state, so its unlikely that we can actually get down to a single shared state. -- UIKit's state (nor the ones in the other platform's UI frameworks) are not multithreaded.

radiosilence commented 3 years ago

@sercand could you possibly share any more examples/info of how to do this? I'm interested in creating a iOS/Android WebSocket server that talks to React Native via JSI (currently I am using two different WS implementations in Java/Swift and it would be an interesting experiment to see if it is possible to have one rust codebase for it)!

terrysahaidak commented 3 years ago

@radiosilence React Native Reanimated 2 uses JSI really intensively where you can access synchronously variables stored in C++ on JS thread and also call some functions on JS which are defined in C++ etc.

ghost commented 3 years ago

@radiosilence @terrysahaidak I've just been poring over the Reanimated source code myself, trying to find the answer to the question I asked above. It seems I was right that callbacks to JS go via the bridge, and that something named CallbackInvokerHolder is involved. I've gotten as far as passing the holder into my JNI code but now I'm stuck as I've no idea how I'm supposed to extract the CallbackInvoker from the holder. Could someone join the dots for me? Reanimated seems to call getCallInvoker but, when I try, JNI throws a NoSuchMethodError. Thanks.

chrfalch commented 3 years ago

@sdc395biosite I'm not entirely sure what you are trying to do here? You are talking about the bridge but want to call via JSI? Remember that JSI replaces the bridge - but you should be able to get a pointer to the current jsi:runtime through the bridge on startup. Just remember that when you are running the remote web executor (debugging) the runtime won't be available.

terrysahaidak commented 3 years ago

@sdc395biosite it's not true, no bridge is used in Reanimated 2 sources. In this particular example, CallInvoker is used only to trigger asynchronously some JS function defined on JS Thread Context from the JS Context running on UI Thread (yeah, separate one).

Here is an example of running a function from JSI:

  1. Define a function in JS: https://github.com/software-mansion/react-native-reanimated/blob/028f00845558d2a63c15caef9e719dd838dc13a8/src/reanimated2/core.js#L46-L88
  2. Call JSI Native method to pass it to C++ (string representation of it) https://github.com/software-mansion/react-native-reanimated/blob/028f00845558d2a63c15caef9e719dd838dc13a8/src/reanimated2/NativeReanimated.js#L13-L15
  3. Define module spec for this native method: https://github.com/software-mansion/react-native-reanimated/blob/master/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp#L5-L13
  4. Define the native method itself: https://github.com/software-mansion/react-native-reanimated/blob/master/Common/cpp/NativeModules/NativeReanimatedModule.cpp#L96-L99
  5. Here is a part which stores the function in C++: https://github.com/software-mansion/react-native-reanimated/blob/master/Common/cpp/SharedItems/ShareableValue.cpp#L86-L91
  6. Call it with or without this: https://github.com/software-mansion/react-native-reanimated/blob/master/Common/cpp/SharedItems/MutableValue.cpp#L43-L46

Perhaps, you won't be able to call that function using JNI directly in Java/Kotlin, but I guess there is already some wrapper for this, take a look at fbjni and recent sources of React Native.

Update: In this example, the module spec is used for TurboModules to work. The Codegen project will allow us to skip that part since all that code will be generated from the definition of the module written in Flow or TypeScript.

If you don't plan to use TurboModules right now, there is a way where you can do everything by yourself. Here is an example of Reanimated 1 API "bridge" written in C++ with JSI, calling Java code using JNI I wrote almost a year ago when I had almost no knowledge and experience in C++: https://github.com/terrysahaidak/reanimated-jsi/blob/master/jsi/android/ReanimatedJSI.cpp

Take a look at this get method. It's basically the same thing Codegen generates us for TurboModules: https://github.com/terrysahaidak/reanimated-jsi/blob/master/jsi/android/ReanimatedJSI.cpp#L136

Also, lots of the code I wrote here is automated by Codegen and TurboModules such as resolving and storing references to Java classes

Here is an example of such generated file: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/fbreact/specs/jni/FBReactNativeSpec-generated.cpp

As well as the generated specs for Java classes, for example: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAccessibilityInfoSpec.java

ghost commented 3 years ago

@terrysahaidak With much help from Reanimated 2, I now have a (nearly) working JSI implementation of my SQLite wrapper for RN. One last puzzle remains, and I'm hoping you'll be able to provide some insight.

When I resolve a Promise that I have created on the native side and returned to JS, my app does not respond until I interact with it. It is as if the JS thread, having just resolved the promise, fails to continue at the awaiting location. If I physically interact with the App's UI, JS springs to life and continues with the resolved value.

Is there something I need to do, in addition to resolving the promise, the get JS to continue?

terrysahaidak commented 3 years ago

I guess @chrfalch can help here, he has a lot of experience with JSI. But I saw a mention of this problem already. Also, perhaps @shergin or @Kudo can help here.

chrfalch commented 3 years ago

Could you provide some code snippets to describe what you are doing? Like some isolated code from both the js/native sides?

mrousavy commented 3 years ago

I think it would be useful to many people if someone who knows their stuff could do a short article with code snippets showcasing JSI and TurboModules stuff, mainly because even the current official Native Modules docs aren't very detailed either.

chrfalch commented 3 years ago

@mrousavy I've already written up a few articles about the topic:

What I believe should be clear is that JSI is not some magic sauce that will change how we write our React Native apps. JSI is an interface (based on the interface implemented by the JSC engine) that has been added to React Native so that the bridge can be removed by letting native code and JS interface directly. Our apps will eventually run quicker and more reliable with the new UI Architecture called Fabric that uses JSI for everything UI related.

The interface lets us call methods on the native side directly from JavaScript - but there is a lot of details and hidden stuff going on in how it is implemented in React Native (just look at how TurboModules are implemented, and how JS engines like JSC and Hermes are deployed and initialized).

To be able to provide greate developer experience, we are still somewhat limited to the async / await pattern when calling into native code from JS - this has to do with the fact that when debugging we need to run a remote JavaScript engine (Chrome) and interface using messages that are dispatched between our device / simulator and our development tools. (It is not possible to debug your code when enabling TurboModules AFAIK).

From looking at the source code in React Native there are still a lot of native modules that will continue to be in use when running in debug mode, and they all have corresponding TurboModules that are used in a production environment to speed things up at runtime, meaning that we'll still have to live with getting async callbacks from native when calling functions - the big difference will be that the bridge (and it's serialize / deserialize form of communication) can be dropped alltogether - giving us a lot of performance benefits in our release builds.

JSI has a public, stable and well-known API, but the documentation is lacking - leading to giving the React Native core developers a lot more flexibility in how they implement and use it in React Native - there are a lot of changes going on to ensure backwards compatibility and avoid any regressions.

My understanding is that JSI, Fabric and TurboModules will be released and made available for all React Native developers, and then there will be a migration path later for native modules to be moved over and republished as TurboModules. We've also seen evidence that Hermes will be made available on iOS (Build Hermes for iOS), and this will in turn make it possible to write a new set of debuggers and tools that eventually might lead to a better experience writing code that interfaces between JS and native in a well defined way.

I'm also a strong believer in using C++ as the language for writing native logic - and TurboModules and JSI is basically a C++ feature - making it easier for us to create cross platform logic on the native side as well as on the JS side.

Disclaimer: If I'm wrong in any of my assumptions or explanations in this post, please provide feedback and I'll try to correct it - I think it is important that the community knows what these concepts and technologies are for, and what they're not for.

ryantrem commented 3 years ago

@bghgary and I just went through this for Babylon React Native with lots of help from @rsnara. Here are the things we learned that I think will be helpful to others:

You can see the full set of changes we made to Babylon React Native to start using CallInvoker here: https://github.com/BabylonJS/BabylonReactNative/pull/97

urbien commented 3 years ago

re-posting here a response on twitter from @fkgozali regarding TurboModules and Codegen in RN 0.64 https://twitter.com/fkgozali/status/1335004270991536129?s=21

As long as the modules are specific to your app, you can follow RNTester setup to enable it. All relevant code is already on master and will be included in 0.64. The setup is still rough and not very stable yet, but we’re planning to iterate further on this in early 2021.


edited by @kelset: to add text from tweet

mrousavy commented 3 years ago

What's the current optimal solution to install HostFunctions into the jsi::Runtime? I have been simply installing them from my native module, but that lead to race conditions/threading issues because that was being invoked on the Native Module Thread, when it really should only be called on the JS thread.

I have tried to play around with JSIModule, JSIModulePackage, etc only to find out that that's not yet actually usable without creating a whole TurboModule. Also I have tried to dispatch to the JS Thread, but that didn't work because the HostFunctions aren't immediately installed when JS starts to execute.

I've created an issue for this here: https://github.com/facebook/react-native/issues/31197, would love to hear some suggestions.

/cc @chrfalch @ryantrem @terrysahaidak @RSNara

DEVfancybear commented 3 years ago

Can you tell me JSI's current progress, how long will it take to release?

minhaics commented 3 years ago

I've been standing here for 3 years waiting for this new architecture, I love react native

e6a5 commented 3 years ago

@hcminhit Waiting is a sign of true love and patience :)

fkgozali commented 3 years ago

Can you tell me JSI's current progress, how long will it take to release?

Could you clarify what you need with JSI? Did you just mean getting access to the VM via JSI abstraction? If so, that's already possible today. In fact the JSIExecutor C++ impl today is already accessing the VM using JSI for a while now. All JSI code is already in github: https://github.com/facebook/react-native/blob/master/ReactCommon/jsi/jsi/jsi.h

If you're trying to access the VM to do something with it, you can also try accessing with a logic you can add to your app like in RNTester:

iOS:

Android:

Note that while this work, you'll be responsible to ensure the access to the VM is safe.


Another alternative is to just write your own subclass of TurboModule C++ class and treat it like a "NativeModule", just in pure C++ (no Java/ObjC). Example: https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/ReactCommon/react/nativemodule/samples/ReactCommon/NativeSampleTurboCxxModuleSpecJSI.h#L19, which you can provide in your app like in RNTester: https://github.com/facebook/react-native/blob/master/packages/rn-tester/RNTester/RNTesterTurboModuleProvider.mm#L25

Note: the latter requires TurboModule to be installed in your app, and we're working on creating a playbook for apps in OSS this year for clearer integration, as mentioned in https://github.com/react-native-community/discussions-and-proposals/issues/40#issuecomment-801472114.


For general updates regarding the new architecture, we're also preparing some writeup about it as mentioned in https://github.com/facebook/react-native/issues/31469#issuecomment-831476590. Stay tuned.

elicwhite commented 3 years ago

I think the tl;dr of @fkgozali's comment is that JSI has already shipped and React Native releases have been using it for a while. For app authors there is no user facing change, it is an implementation detail of React Native. The TurboModule system (that is still in progress) will take advantage of it more. If you are a module author and want to do custom things with it directly, the links Kevin provided might help you out.

giangdinh commented 3 years ago

Does new all of the "new" architects ready? 2021 will be gone fast.

gillpeacegood commented 3 years ago

Another alternative is to just write your own subclass of TurboModule C++ class and treat it like a "NativeModule", just in pure C++ (no Java/ObjC). Example: https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/ReactCommon/react/nativemodule/samples/ReactCommon/NativeSampleTurboCxxModuleSpecJSI.h#L19, which you can provide in your app like in RNTester: https://github.com/facebook/react-native/blob/master/packages/rn-tester/RNTester/RNTesterTurboModuleProvider.mm#L25

Note: the latter requires TurboModule to be installed in your app, and we're working on creating a playbook for apps in OSS this year for clearer integration, as mentioned in #40 (comment).

https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/ReactCommon/react/nativemodule/samples/ReactCommon/SampleTurboCxxModule.cpp

Is it possible for the getValueWithCallback & getValueWithPromise to be genuinely asynchronous and if so could you give any pointers as regards how to achieve that?

kelset commented 3 years ago

(with the help of @mrousavy I've added a list of libs that use JSI to the top post, so that you can use them as references)

ammarahm-ed commented 3 years ago

react-native-mmkv-storage also uses JSI to communicate with native side. To make secure storage work in the library I have also accessed Java classes via C++ JNI. It means that any current module that uses the old bridge can easily update their library to use JSI instead keeping the functionality same by accessing java objects from JNI. This also helps remove the need to async/await for getting small data.

ammarahm-ed commented 3 years ago

Hey everyone, if you are looking to build a JSI module and don't understand much by looking at the code of libraries provided above, You can read my blog post where I have explained everything from scratch in detail.

Jarred-Sumner commented 3 years ago

JSC's C API (which React Native uses) does a lot of locking which makes any function calls into JSI from very large loops slow on iOS.

There's an open issue from 2019 about it here: https://bugs.webkit.org/show_bug.cgi?id=203463, but it seems inactive. Might be worth bumping it.

flexsurfer commented 3 years ago

Hey everyone, is there any example of how to call JS function from c++ ? i found only examples with calling c++ from JS, thanks

mrousavy commented 3 years ago

@flexsurfer

If it's something global, such as a Promise, use this:

auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
auto promise = promiseCtor.callAsConstructor(runtime, ....);

If it's an anonymous variable (const x = () => ...), then you have to pass it to the C++ func as an argument:

auto nativeFunc = jsi::Function::createFromHostFunction(runtime,
                                                         jsi::PropNameID::forAscii(runtime, "someFunc"),
                                                         1,  // a function
                                                         [](jsi::Runtime& runtime, const jsi::Value&, const jsi::Value* arguments, size_t count) -> jsi::Value {
    auto func = arguments[0].asObject().asFunction();
    return func.call(runtime, jsi::Value(42));
});
flexsurfer commented 3 years ago

thanks a lot, it works jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "myFunction").call(jsiRuntime);

but if I'm trying to pass a parameter I have an error:

jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "myFunction").call(jsiRuntime, value);

image

EDITED: seems like it's the case

// TODO(cjhopman): this seems unsafe unless we require that it is only called on the main js queue.
@property (nonatomic, readonly) void *runtime;
mrousavy commented 3 years ago

This is not the ideal place to discuss this. Post this on twitter and tag me (@mrousavy), but I'm guessing you called this code on some thread that's not the JS thread (which is exactly what your screenshot says)

jahead commented 3 years ago

Hey, not sure where/who I should post this but I'm going to post it here. Sorry for the spam.

What's the best approach to exposing a JSI Object that can act like an EventTarget in js, our use case is that want to create JsObjects in the JSI that have onevent listeners?

We've read as much of the code base as I think we can; we've seen that uimanger has constructs for eventemitters, but that codebase seems to imply that the requires the class be subclass of a view/node.

To be clear, we aren't looking to dispatch events, that can happen on the java side, but we would like to be able to expose a JSI Object that supports EventTarget functionality on the global namespace without having to wrap the 'native' object with a js object that interfaces with NativeEventEmitter.

We have also read the Re-animated code base that has AFIAK their own solution for a cpp driven event emitter, but we see that as a bit of overkill?

Basically it would be great to have a class we can implement that would enable the JSI object to marshal the event e.g MyJSObject -> EventTargert -> HostObject or the next best thing.

Btw this going for an OSS project if that counts for anything..

mrousavy commented 3 years ago

@jahead why do you absolutely need to use JSI for this now? It's definitely possible, but you need to create a JSI HostObject which is exposed to JS, that contains a list of listener functions and then calls them when you trigger it - but

  1. The setup for Android is really hard, you have to use JNI for C++ and if it's an instance you probably want to use fbjni - another thing to learn.
  2. The installation into the JS runtime is a bit tricky
  3. You have to add custom converters for any values (ObjC values -> JS values, Java values (C++ JNI bindings at least) -> JS values)

Why not just use a Native Bridge Module for this now? Once TurboModules land, your Native Bridge Module can easily be migrated to a TurboModule with just a few minor changes, and then it uses JSI. No C++ magic needed.

jahead commented 3 years ago

The module in question requires by spec to need a number of performant synchronous calls and we want to use the dtor for clean up (yes we are aware that it there's no guarantee around GC), we have used the jni for number of internal projects, and we have the initial plumbing for to use the build JSObjects. So 1, 2, 3 not a complete blocker for us, we have a reasonable/working solution - minus some head bumps :D.

What we lack in understanding is whats the appropriate way JSI/C++ to achieve something like an EventTarget class so our child classes can expose event listeners.

We have read the interactions with https://github.com/facebook/react-native/blob/1465c8f3874cdee8c325ab4a4916fda0b3e43bdb/ReactCommon/react/renderer/core/EventTarget.h and the associated classes to how react native core is doing something similar, but it all seams to be tied to the view?

basically is there a nice way to handle this currently or do we have standup our own EventTarget/Scheduler/Dispatcher/Emitter pipeline? as I currently see it we have two options

  1. wrap the jsi object with a js object that bundles in the NativeEmitter
  2. build our own events infrastructure

but we want to make sure the react native team/community doesn't see a different way we should be doing this. turbo modules isn't really going to solve our issue here, we are trying to expose a Native backed JSObject, we would still have the events problem. just less bolierplate.

if there is any information regarding the subject please let me know.

ryantrem commented 3 years ago

If I'm understanding your scenario correctly, then implementing events as a callback list that you invoke from native code seems like a pretty reasonable solution (we do this a lot in Babylon Native). As @mrousavy said though, this gets complicated (especially on Android due to fbjni) because you need to get back on the js thread. I posted some details about this earlier in the thread: https://github.com/react-native-community/discussions-and-proposals/issues/91#issuecomment-713027687. It's slightly easier on RN 0.64 plus because it generates librurbomodulejsijni.so for you, but still complicated. As @mrousavy said though I'd expect this to be much easier with TurboModules because I believe they provide you with the js CallInvoker (to get on the js thread).

mrousavy commented 3 years ago

This seems to be a great time to ask: What's the future of native C++ Android libraries? Currently a lot of community libraries that contain native C/C++ code are being pre-built into a .aar format. This has a lot of issues:

  1. Autolinking doesn't work, you have to create a dummy java file matching that path
  2. Release cycles get slower because everytime you want to release something you have to build one (or multiple) .aars
  3. If you have version specific code (RNVERSION > 64, RNVERSION <= 64, ..), you have to build one .aar per RN version, which is horrible. Reanimated currently has 4 .aars and counting for each major RN version (62, 63, 64, 65)
  4. If you have to use another native library (such as reactnativejni or fbjni), you have to link it at build time (which is when you build your aar for distribution, and not when the user builds the app!) - makes it hard to upgrade dependencies such as fbjni.
  5. If you use the runtimes (JSC, Hermes, V8) you have to create one .aar per runtime, that's what Reanimated and VisionCamera does - so Reanimated is now up to 8 aars (62 JSC, 62 Hermes, 63 JSC, 63 Hermes, ....)
  6. Users cannot quickly test local changes or patches - they have to try building it from source and that's really really difficult.
  7. Users cannot help debugging a aar library
  8. Package size increases per aar

I see the following solution:

  1. Distribute every library as source and require users to install NDK
  2. Enable prefab for all react native native libraries to make the installation of dependencies (fbjni, reactnativejni, jsi) in third party packages easier.

What do you guys think?

chakrihacker commented 3 years ago

@mrousavy Looks like we need a RFC for this topic

ammarahm-ed commented 3 years ago

As promised, I have written my next blog on JSI where I talk about converting Native Modules to JSI Modules on Android and iOS.

Read the full blog on the link below:

React Native JSI: Part 2 - Converting Native Modules to JSI Modules

rangav commented 3 years ago

Here is roadmap update from react native team

https://reactnative.dev/blog/2021/08/19/h2-2021

Looks like they are planning to release new architecture by end of this year.

stephenkopylov commented 2 years ago

Hi guys!

Is there any easy way to run callback, passed from JS asynchronously?

Right now because of non-thread safety nature of JSI runtime, it's really difficult to do something like this:

auto foo = Function::createFromHostFunction(jsiRuntime, PropNameID::forAscii(jsiRuntime, "foo"), 0,
    [](Runtime & runtime, const Value & thisValue, const Value * arguments, size_t count) -> Value {

        Function callback = arguments[0].getObject(runtime).getFunction(runtime);

        std:: function c_callback = [ & runtime, & callback](const char * message) {
            String string = String::createFromUtf8(runtime, message);

            callback.call(runtime, string);
        };

        asyncModuleRunningSomeCode -> run(data.c_str(), c_callback);

        return nullptr;
    });

jsiRuntime.global().setProperty(jsiRuntime, "foo", std::move(foo));

I've seen workaround made by RNMultithreading's creator here but it looks little bit too complicated 🤔

Actually we really need something like

facebook::jsi::runOnJSThread([](){
   foo();
});
mrousavy commented 2 years ago

@stephenkopylov Hey, RNMultithreading creator here, what you're looking for is a reference to the CallInvoker. That's a property on the RCTBridge (iOS) and CatalystInstance (Android), I think I use this in Multithreading and VisionCamera and JSI-Contacts. Also make sure to move your callback JSI Value, capturing by reference is a bit dangerous since it might've already been GC'd

stephenkopylov commented 2 years ago

@mrousavy thank you for your answers

CallInvoker

Yeap! And right now we have to use some kind of native wrapper (just like here in Reanimated) to have an ability to call something on the same thread that our function was called from

I thing It wold be really useful if we could do it using only <jsi/jsi.h> header

chrfalch commented 2 years ago

The <jsi/jsi.h> headers are part of the JSI specification - maybe it would be better to put it in TurboModuleUtils which contains extensions like promises etc? That way we won't need to ask the hermes/jcs/v8 engine maintainers to extend their implementations.

chrfalch commented 2 years ago

Given that you have a reference to the JS runtime and to the callInvoker, what you need is basically a wrapper that looks something like this:

void runOnJavascriptThread(const jsi::HostFunction& func) {
  callInvoker->invokeAsync([runtime, callinvoker, func = std::move(func)]() {
      func->call(runtime, nullptr, 0)
  });
}

(This was freestyled)

stephenkopylov commented 2 years ago

@chrfalch you're absolutely right about header placement

Already having the Runtime the one question lasts - how to get pointer to current CallInvoker instance inside the jsi module...

chrfalch commented 2 years ago

@chrfalch you're absolutely right about header placement

Already having the Runtime the one question lasts - how to get pointer to current CallInvoker instance inside the jsi module...

You need to find a way to pass it down - like when constructing your class or something?

I've added a small utility class called PlatformContext which contains these objects in my projects - and then I pass a pointer to that around to the objects that needs it.

stephenkopylov commented 2 years ago

Well I figured it out, thank you guys - everything works now 🎉

For all of people who will face the same situation with lack of official documentation I can definitely recommend you this repo - it perfectly describes all you need to know about JSI, turbo modules and calling JS function from another threads

khanhduy62 commented 2 years ago

Any document or video that I can learn how JSI works or something like that (I come from Viet Nam so maybe my English skill is not good)

laptou commented 2 years ago

Is there any integration between JSI and Native UI components yet? I'm trying to figure out how to pass a reference to a piece of native state (ex.: contained inside of a host object) as a prop to a native UI component, and so far the best idea I've come up with is passing a pointer around as a string, which is dodgy at best ...

ryantrem commented 2 years ago

It sounds like you are looking for the new Fabric UI architecture (JSI-based), which I believe is not usable yet: https://reactnative.dev/docs/fabric-renderer

mfbx9da4 commented 2 years ago

I've noticed some issues with using promises together with async JSI functions. I've raised an issue https://github.com/facebook/react-native/issues/33006

Has anyone here experienced something similar?