Tips to execute asynchronous operations from a local JavaScript package using Javet in an Android application
Hello @caoccao,
Firstly, kudos on your efforts to revive j2v8 and keep it active. I have a specific requirement where I need to utilize a JavaScript interface file within my Android application. My goal is to call this file and capture its output. Could you please provide some guidance on how I can achieve this using Javet?
Note: There will be asynchronous operations performed within the interface class.
Initially, I explored using GraalVM, but I found it to be more complex to integrate compared to other options. Additionally, it might have a larger footprint and is not as widely adopted in the Android ecosystem. Therefore, I shifted my focus to Javet after learning about its offerings and ease of integration.
Thank you!
Hi @jbatra-umeey ,
Thank you and welcome.
There are 2 typical options for your reference.
- Wrap that call in a Java
Futureand let JS code wait thatFuturefor its completion. - Wrap that call in a JS
Promiseand let JS code wait thatPromisefor its completion.
Both options shift the workload to the worker thread, and let the main thread wait for the completion. I prefer (2) as it's a more natural one. The challenge of (2) is it's not easy to master Promise in Javet. This doc could be a good start. Then, the Javet unit test may give you some in-depth ideas. And my other project Javenode may show you how to write production quality code with Promise. You may join the discord server to further discuss with me in real-time.
Please let me know if you have any questions. Good luck!
@caoccao thanks for the prompt response. PFB, a little more context
Description:
I'm exploring the possibility of utilizing Future/Promise calls within Javet for a specific requirement. The setup involves a file named wrapper.js which heavily depends on the src folder in its directory structure. The goal is to call a function from this file, either using const asyncOperationPromise = performAsyncOperation(); or asyncOperationFuture.then(function(result) { console.log('Future Result:', result); });, based on the implementation in the V8 runtime.
I'm curious about whether Javet supports this functionality, particularly for loading from the classpath and consuming the output. Any insights or guidance on how to achieve this would be greatly appreciated.
Additional Context:
- The
wrapper.jsfile resides within a specific directory structure, heavily relying on thesrcfolder. - The intention is to call a function from within
wrapper.js, leveraging either Promise or Future, depending on V8 runtime implementation - Looking for support or suggestions on how to handle this scenario effectively within Javet.
Sample code in wrapper.js
function performAsyncOperation() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
const result = 'Async operation completed';
resolve(result); // Resolve the promise with the result
}, 2000); // Simulate a 2-second delay
});
}
// Using Promise's then() method to handle the result
asyncOperationPromise.then(function(result) {
console.log('Result:', result);
}).catch(function(error) {
console.error('An error occurred:', error);
});
// Using Future-like object to handle the result
class Future {
constructor() {
this._result = null;
this._callbacks = [];
}
setResult(result) {
this._result = result;
this._callbacks.forEach(callback => callback(result));
}
then(callback) {
if (this._result !== null) {
callback(this._result);
} else {
this._callbacks.push(callback);
}
}
}
const asyncOperationFuture = new Future();
performAsyncOperation().then(function(result) {
asyncOperationFuture.setResult(result);
});
A simple answer: Yes.
According to your reply, I do see there is quite some work to do to make it work.
The JS code seems to be like a Node.js application. Javet doesn't support Node.js on Android, but some friends made it partially work. Let's assume you want to make it work in the Javet V8 mode. You'll have to:
- Create a bundle build: It seems you are more in favor of running it as the folder structure shown in your reply. Yes, Javet allows that, but you'll have to write your own module resolver to tell V8 where to locate the JS files because V8 knows neither the file system, nor the network. Creating a bundle build would save you the effort on your own module resolver.
- Polyfill the missing Node.js API: V8 is purely a script engine that doesn't have
setTimeout,window, etc. All non-ECMA API are provided by Node.js, Chrome. That's also why project Javenode was created.
Back to the JS application, I suppose the so-called async is:
- It's a sync call, but you want it to be async in Javet. Well, you don't need to do any tricks. That's a long talk. Better contact me at discord.
- It's an async call. The built-in
Promiseis the one. Be careful withPromisein Javet. CallingV8Runtime.await()is required to pump the event loop. The Javet unit test demonstrates that well.
@caoccao, I appreciate your response. After reading your comment, I'm still uncertain about how to proceed. I have a general idea of the steps required to build a bundle from a Node.js application, but I'm unsure about how to integrate it with the V8 runtime. Are there any starter projects available that could provide guidance and direction? Additionally, is there anything specific within the Javanode project that I should examine for insights?
I suggest you to start from a simple script so that you could get familiar with the Javet way, then add more features to the script. Ping me at discord would be more efficient, I suppose.
@caoccao Sure, lets connect on Dissord