在Java中通过GraalVM调用JS异步函数并获取返回值的方法
GraalVM处理JavaScript异步函数的常见问题
1. 能否使用GraalVM等待JavaScript异步函数解析并获取其输出?
可以,GraalVM提供了标准API处理JavaScript Promise对象,完全不需要依赖字符串解析这种不规范手段。
2. 执行代码后,result返回包含额外信息的Promise对象而非预期字符串,原因是什么?
JavaScript中所有async函数的返回值都是Promise对象,不管函数内部是同步逻辑还是异步操作。你的代码里,ctx.eval执行脚本后返回的是dummyAsyncFunction()调用产生的Promise实例——哪怕你在脚本里用.then()处理了Promise,.then()本身也会返回新的Promise,脚本执行结果就是最开始的那个Promise,所以Java端拿到的自然是Promise对象,而非最终的字符串结果。
3. 如何正确获取异步函数的返回值?
推荐两种规范的实现方式:
方式一:在JavaScript脚本中同步等待结果
利用await关键字在脚本内部等待异步函数完成,将结果存入全局变量,再由Java端读取:
public void main() { try (Context ctx = Context.newBuilder("js") .allowAllAccess(true) .option("engine.WarnInterpreterOnly", "false") .build()) { String combinedScript = """ async function dummyAsyncFunction() { console.log("dummyAsyncFunction()"); let start = new Date().getTime(); while (new Date().getTime() - start < 2000) {} return "thanks for waiting"; } // 立即执行异步函数并await结果,存入全局变量 globalThis.asyncResult = await dummyAsyncFunction(); """; ctx.eval("js", combinedScript); // 从JS全局绑定中获取结果 Value result = ctx.getBindings("js").getMember("asyncResult"); System.out.println("result: " + result.asString()); } catch (Exception e) { e.printStackTrace(); } }
方式二:在Java端直接处理Promise对象
通过GraalVM的Value API调用Promise的then方法,传入回调获取结果:
import java.util.concurrent.atomic.AtomicReference; public void main() { try (Context ctx = Context.newBuilder("js") .allowAllAccess(true) .option("engine.WarnInterpreterOnly", "false") .build()) { String combinedScript = """ async function dummyAsyncFunction() { console.log("dummyAsyncFunction()"); let start = new Date().getTime(); while (new Date().getTime() - start < 2000) {} return "thanks for waiting"; } // 返回Promise对象供Java端处理 dummyAsyncFunction(); """; Value promise = ctx.eval("js", combinedScript); // 校验是否为Promise对象 if (promise.hasMember("then")) { AtomicReference<String> resultRef = new AtomicReference<>(); // 调用then方法,传入回调函数获取结果 promise.invokeMember("then", (Value message) -> { resultRef.set(message.asString()); return null; }); // 本示例为同步忙等场景,结果已就绪;若为真异步操作,需添加合理等待逻辑 System.out.println("result: " + resultRef.get()); } } catch (Exception e) { e.printStackTrace(); } }
关于字符串解析方式的问题
你之前尝试的字符串解析方式完全不规范:Promise的toString()输出格式没有统一标准,不同JavaScript引擎(或GraalVM版本)可能会修改这个输出格式,一旦格式变动,你的解析逻辑就会直接失效,完全不具备可靠性和可维护性。
内容的提问来源于stack exchange,提问作者user17281101
相关产品推荐
相关产品推荐

