如何存储来自 ScriptManager 的函数句柄供以后使用?

How to store function handles from ScriptManager for later usage?

tl;博士:
do/can 我如何将多个 js 函数的函数句柄存储在 java 中以供以后使用?目前我有两个想法:

  1. 创建多个 ScriptEngine 实例,每个实例包含一个加载函数。按列将它们存储在地图中,列表中每列有多个条目。看起来开销很大,具体取决于 'heavy' ScriptEngine 实例是如何...

  2. 一些 Javascript 解决方案将同一目标字段的方法附加到数组。还不知道如何从 java 端访问它,但也不喜欢它。想让脚本文件尽可能愚蠢。

     var test1 = test1 || [];
     test1.push(function(input) { return ""; });
    
  3. ???

想法或建议?


告诉我更多:
我有一个项目,其中有一个包含脚本文件的目录(javascript,预计将来会增加一百多个文件)。这些脚本文件的命名方式如下:test1;toupper.jstest1;trim.jstest2;capitalize.js。分号之前的名称是脚本将处理的 column/field ,分号之后的部分是人类可读的描述文件的作用(简化示例)。因此,在此示例中,有两个脚本将分配给“test1”列,一个脚本将分配给“test2”列。 js-function 模板基本上是这样的:

    function process(input) { return ""; };

我的想法是,在服务器启动时加载(和evaluate/compile)所有脚本文件,然后在需要时按列使用加载的函数。到目前为止,还不错。

我可以 load/evaluate 使用以下代码的单个函数。示例使用 GraalVM,但也应该可以用其他语言重现。

    final ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
    final Invocable invocable = (Invocable) engine;
    
    engine.eval("function process(arg) { return arg.toUpperCase(); };");
    var rr0 = invocable.invokeFunction("process", "abc123xyz"); // rr0 = ABC123XYZ

但是当我 load/evaluate 下一个具有相同名称的函数时,前一个函数将被覆盖 - 从逻辑上讲,因为它具有相同的函数名称。

    engine.eval("function process(arg) { return arg + 'test'; };");
    var rr1 = invocable.invokeFunction("process", "abc123xyz"); // rr1 = abc123xyztest

我就是这样做的。

使用 Graal.js 的推荐方法是通过多语言 API:https://www.graalvm.org/reference-manual/embed-languages/

使用 ScriptEngine API 可能不一样,但这里是使用多语言 API.

的示例
  1. 将函数定义包装在()
  2. return Java
  3. 的函数
  4. 图中未显示,但您可能构建了一个从列名称到要在其上调用的函数列表的映射。
  5. 对数据调用函数。
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;

public class HelloPolyglot {
    public static void main(String[] args) {
        System.out.println("Hello Java!");
        try (Context context = Context.create()) {
            Value toUpperCase = context.eval("js", "(function process(arg) { return arg.toUpperCase(); })");
            Value concatTest = context.eval("js", "(function process(arg) { return arg + 'test'; })");

            String text = "HelloWorld";
            text = toUpperCase.execute(text).asString();
            text = concatTest.execute(text).asString();

            System.out.println(text);
        }
    }
}

现在,Value.execute() return 是一个 Value,为了简单起见,我用 asString() 强制转换为 Java 字符串,但你没有为此,您可以对 Value 进行操作(这里是 API 的值:https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html)。