You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:32:05