Closed kelset closed 2 years ago
Is there any way to call the callback passed from javascript async . I have a java method with async listener like below
static public void identifyLanguage(String text) {
LanguageIdentifier languageIdentifier = LanguageIdentification.getClient();
languageIdentifier.identifyLanguage(text)
.addOnSuccessListener(v -> {
})
.addOnFailureListener(e -> {
});
}
I invoked the c++ method from javascript through jsi and the c++ method called this static java method . the problem is I passed in an anonymous callback from javascript to receive calling result , but as you can see the result from java is asynchronous . the registered c++ method cannot get the result synchronous . how can I invoke the passed in callback once the SuccessListener invoked ?
@yaaliuzhipeng the main thing you need to achieve this is react::CallInvoker
. When you'll get all you need to do is something like this:
#include <ReactCommon/CallInvoker.h>
#include <ReactCommon/TurboModule.h>
#include <ReactCommon/TurboModuleUtils.h>
static Value foo(Runtime &rt, TurboModule &turboModule, const Value *args, size_t arg_count) {
std::weak_ptr<CallbackWrapper> callbackWrapper = react::CallbackWrapper::createWeak(args[0].getObject(rt).getFunction(rt), rt, turboModule.jsInvoker_);
callYourJavaMethodWithAsyncCallbackAsArgument([callbackWrapper](){
auto strongWrapper = callbackWrapper.lock();
if (!strongWrapper) {
return;
}
strongWrapper->jsInvoker().invokeAsync([callbackWrapper]() {
auto strongWrapper2 = callbackWrapper.lock();
if (!strongWrapper2) {
return;
}
strongWrapper2->callback().call(strongWrapper2->runtime()); //calling your async callback
strongWrapper2->destroy();
});
};
);
return 0;
};
PS: I'd recommend you to use CallbackWrapper - it's really useful if you are not sure that JSRuntime (ant all it's objects including your callback) is still alive
PPS: Don't forget to destroy all your callbacks in TurboModule's destructor
PPPS: as I mentioned before - here's a good example of TurboModule with JSCallInvoker in it
How do I get a shared_ptr
to the JS runtime on Android? It seems to be exposed as a shared_ptr
on iOS, which is great b/c I can convert it into a weak_ptr
and this lets me know when the runtime is destroyed, but on Android it seems that I just get a raw pointer with no easy way to track the lifetime of the runtime.
Is there any recommended way to release native resources held by the HostObject when it's being garbage collected? (Assuming HostObject gets GCed when there are no references to them in JS world and when the garbage collector runs)
Yes, the HostObject's C++ destructor.
Great. Thank you @mrousavy. Tried putting a destructor and noticed it gets called sometimes but not consistently when we release the variable references from JS. Maybe because it's still not garbage collected? In that case, I guess it would be safer to provide some function in HostObject that we can manually call to release resources? Let me know if I am understanding it correctly.
Yes, JS memory management works different than C++' memory management. The HostObject only gets deleted when the GC runs (which btw might even be on another Thread, so be careful when doing JSI or JNI stuff).
See react-native-vision-camera's Frame Host Object for an example :)
Is the lifetime of the CallInvoker
tied to the lifetime of the Runtime
? As in, if I schedule a callback using invokeAsync
, is it guaranteed that the runtime will still exist when the callback is called?
@DominickVale install React Native into a node_modules
folder, then add the following paths to your header search path:
node_modules/react-native node_modules/react-native/React node_modules/react-native/React/Base node_modules/react-native/ReactCommon/jsi node_modules/react-native/ReactCommon/callinvoker
You can also get the same headers by downloading the Hermes source code (they are located in the API
folder).
How do you get a reference to the RuntimeExecutor
on iOS? It's available via CatalystInstance
on Android, but I can't find the analogous method on iOS.
Hi, what would be the correct way to have an array of objects constantly being updated and the js side being notified of those changes? All the attempts I've made end up in crashes. I tried callbacks, i tried manually getting the data from a js loop etc. They are all not working at higher speeds (for example less than 50ms)
Hi, I was wondering... Is there was a way to pass an ArrayBuffer from C++ to the JS side? I know there is the getArrayBuffer method to get ArrayBuffer from JS, but I couldn't find anything for the other way around.
Hi, I was wondering... Is there was a way to pass an ArrayBuffer from C++ to the JS side? I know there is the getArrayBuffer method to get ArrayBuffer from JS, but I couldn't find anything for the other way around.
Not currently. There was discussion of this in https://github.com/facebook/hermes/pull/419#issuecomment-747119254 in the past. It's not something on our roadmap, but we would be happy to advise on what we would want to see in a PR.
@JiriHoffmann Does react-native-buffer do what you need?
@DominickVale I've also experienced performance issues with async JSI functions
@JiriHoffmann Does react-native-buffer do what you need?
Not really, it uses memcpy which is the same thing I do.
Hi, I was wondering... Is there was a way to pass an ArrayBuffer from C++ to the JS side? I know there is the getArrayBuffer method to get ArrayBuffer from JS, but I couldn't find anything for the other way around.
Not currently. There was discussion of this in facebook/hermes#419 (comment) in the past. It's not something on our roadmap, but we would be happy to advise on what we would want to see in a PR.
@mhorowitz I would love to give it a try, although I'm not sure if my JSI and C++ knowledge is up to par yet. Maybe a new issue would be helpful so that others can take a look at it as well?
Also I created two JSI libraries if you want to add them to the list:
@JiriHoffmann Does react-native-buffer do what you need?
@DominickVale I've also experienced performance issues with async JSI functions
I'd love to only get performance issues. I literally cannot find a reliable way to get state updates from the c++ side of things. Whether i call a c++ function from javascript every 20ms or i call said javascript function from state hooks on the c++ side it crashes in a non-deterministic way 80% of the time (at least to me). The worst part is actually the fact that it works most of the time but it crashes in this random way. I tried debugging but the stack trace doesn't make sense to me as it's just internal JSI stuff and nothing regarding what I'm doing natively. What i need to do is pretty simple... I just want real-time data from the c++ side. It's been a month and still no solution.
@DominickVale that sounds like a big problem - can you try to isolate it into a repro project and report it (similarly to what @mfbx9da4 did) so that it can be investigated further?
@DominickVale Could there be an issue with accessing the Javascript JSI objects from other threads than the JS thread? This could be a source of unreliable crashes like this.
Not sure if this is the right place for this, if so it would be great if you could refer me to where this can be discussed
I wanted to ask how native modules in the new architecture work compared to "jsi modules".
"jsi modules" below
Libraries implemented using JSI
Will all new native modules (turbo modules) essentially be "jsi modules"?
Is there any need for c++ code in order to implement this or are codegen declarations on the js side enough for synchronous calls to native functions out of the box?
Does calling native function synchronously mean that return values are also returned synchronously ( as opposed to promises or callbacks)?
From my understanding, the bridge will still exist for backward compatibility, so how will migration of legacy native modules be handled? Is it enough to generate a codegen schema for the modules to redirect calls to these modules through the jsi as opposed to the bridge?
I don't want to overwhelm with questions but I feel as if the answers to all of these questions are related... Thanks in advance!
Hey @yotamishak, I spotted my libs there! 😄
"JSI Modules" is what I call my libs that use the bare JSI C++ API to provide fast and synchronous bindings from JS to native (C++).
Turbomodules is an abstraction built ontop of JSI to make it easy for everyone to write native modules that are powered by JSI, without having to touch C++ code.
So yes, Turbomodules (the new native module system for React Native) will use JSI under the hood, just like my libraries. It's just a bit abstracted/wrapped to make it easier, since my JSI Modules are a bit complex in code (lots of C++)
@mrousavy thanks for the quick response I'm well familiar with your libraries and have been trying to pick out part of your code to find a Jsi solution to my use case.
I noticed this repo https://github.com/mrousavy/react-native-jsi-library-template of yours.
So using the new architecture I wouldn't need to use this template at all correct? I would get all of this functionality out of the box?
Yea, when using Turbomodules you won't need my jsi-library-template. Instead, take a look at this guide.
There are some parts that are still not covered by Turbomodules, e.g. custom JSI HostObjects, shared memory ArrayBuffers, and multithreaded JSI Runtimes - which is why MMKV or VisionCamera (the Frame Processors Part specifically) cannot be migrated to a Turbomodule (yet).
I've been investigating solutions that allow you to create JSI HostObjects with the Java/ObjC APIs on Turbomodules and pass them around like normal types (boolean, number, string, object, array), maybe I'll open a PR to react-native core soon
@Kudo
2.5.6 Apps that browse the web must use the appropriate WebKit framework and WebKit Javascript.
If so, why Hermes engine is supported in iOS, does it means that we should use Hermes for JSI & JavasScriptCore for inner WebView. Then we must keep two engine in RN iOS project?
hey folks, since we have an official deep dive discussions section open on this in the ReactWG New architecture, let's close this one and make the conversation progress over there: https://github.com/reactwg/react-native-new-architecture/discussions/categories/deep-dive (there are also some other sections, like Q&A, to ask more specific questions with an easier UX for replying)
Remember that you can apply to the WG (in case you are not in it yet) by applying to the form in the readme.
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)
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.