Javet icon indicating copy to clipboard operation
Javet copied to clipboard

Tips to execute asynchronous operations from a local JavaScript package using Javet in an Android application

Open jbatra-umeey opened this issue 1 year ago • 6 comments

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!

jbatra-umeey avatar Feb 20 '24 14:02 jbatra-umeey

Hi @jbatra-umeey ,

Thank you and welcome.

There are 2 typical options for your reference.

  1. Wrap that call in a Java Future and let JS code wait that Future for its completion.
  2. Wrap that call in a JS Promise and let JS code wait that Promise for 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 avatar Feb 20 '24 15:02 caoccao

@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.js file resides within a specific directory structure, heavily relying on the src folder. JS-Package
  • 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);
});

jbatra-umeey avatar Feb 20 '24 15:02 jbatra-umeey

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 Promise is the one. Be careful with Promise in Javet. Calling V8Runtime.await() is required to pump the event loop. The Javet unit test demonstrates that well.

caoccao avatar Feb 21 '24 00:02 caoccao

@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?

jbatra-umeey avatar Feb 21 '24 09:02 jbatra-umeey

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 avatar Feb 21 '24 09:02 caoccao

@caoccao Sure, lets connect on Dissord

jbatra-umeey avatar Feb 21 '24 10:02 jbatra-umeey