Closed pragmasoft-ua closed 4 years ago
Hi @pragmasoft-ua
thanks for your question.
setTimeout
is not defined in JavaScript (ECMAScript). It is an extension typically provided by the host environment (the Browser, the Node.js framework). This is the reason why you don't have it in our js
binary (providing only pure JavaScript, with few exceptions). The function is available in the graalvm/bin/node
executable.
Starting a node
process from Java with something like context.eval("node", script)
is an interesting idea, that we are investigating on a long-term scale. It is a technical challenge, as both the JVM and Node.js are binary applications, that take control of resources, signals, threads, etc. and don't expect another such application appear on the same process.
We have solved this in the other direction, though. You can start a JavaScript/Node.js application via graalvm/bin/node --jvm
and then use our JavaScript-Java interoperability to move into Java land from there. You need to take about multithreading, but in general, it is possible.
Best, Christian
Was there any workaround to this issue for use with polyglot?
The question is still actual...
setTimeout
is a function that should be implemented by the embedder of the JavaScript engine. It is the same for Node.js. The function that you see there does not come from V8
(the JavaScript engine used by the original Node.js) but is provided by Node.js runtime (= the embedder of the JavaScript engine).
If you embed graal-js
into your Java application then you can use something like
public static void main(String[] args) throws Exception {
Context context = Context.newBuilder("js").allowAllAccess(true).build();
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
TimeoutFunction setTimeout = (fn, delay) -> executor.schedule(() -> fn.execute(), delay, TimeUnit.MILLISECONDS);
// all JavaScript tasks are executed through the executor to ensure a single-threaded access
executor.schedule(() -> {
// define/initialize setTimeout function
context.getBindings("js").putMember("setTimeout", setTimeout);
// try to use setTimeout function
context.eval("js", "console.log('See you in 5s.'); setTimeout(() => console.log('I am back!'), 5000)");
executor.shutdown();
}, 0, TimeUnit.MILLISECONDS).get();
}
@FunctionalInterface
public static interface TimeoutFunction {
void setTimeout(Value fn, int delay);
}
setTimeout
is a function that should be implemented by the embedder of the JavaScript engine
You probably realize that the problem is not with the setTimeout
only. Without the possibility to use 3rd party libraries this feature has almost no value, nobody will implement in java entire node runtime.
I don't understand why you cannot expose the existing node runtime you have already implemented in java to use by java / polyglot developers.
There are 4 years passed since I opened this issue, and still I don't see any popular frameworks emerged using this polyglot feature. The main reason is the lack of possibility of using 3rd party libraries.
I don't understand why you cannot expose the existing node runtime you have already implemented in java to use by java / polyglot developers.
If you want to use Java and Node.js features then you should use graal-nodejs
. Node.js is not a library, it is a runtime. You cannot simply expose its builti-ns in Polyglot API in an arbitrary Java application. There is much more in Node.js (event loop, signals etc.)
You cannot simply expose its builti-ns in Polyglot API in an arbitrary Java application. There is much more in Node.js (event loop, signals etc.)
Really? Just add an entry point to start event loop and expose it as binding? Is it too complex?
still I don't see any popular frameworks emerged using this polyglot feature. The main reason is the lack of possibility of using 3rd party libraries.
That's an interesting point. As far as I know, there are no popular frameworks built on top of Node.js in JVM. The reason to my understanding is there is no need to do so because a genuine Node.js in JVM (not GraalJS) natively supports all kinds of 3rd party libraries. E.g. There are tens of Minecraft mod developers use such a Node.js in JVM solution to bridge the JS scripts with the Minecraft SDK.
When I'm trying to use polyglot context to evaluate simple js script containing global setTimeout function, I get the following error:
ReferenceError: setTimeout is not defined
The same error I obtain when use graalvm js binary.
Though, script works properly, when I execute it using graalvm node binary.
Is there any way to evaluate script from polyglot context in node compatibility mode?
I tried context.eval("node", script) and tried using .option("js.v8-compat", "true") in Context.Builder without any success.