逐步通过ScriptEngine评估的JavaScript代码

Stepping Through JavaScript Code Evaluated by ScriptEngine

本文关键字:JavaScript 代码 评估 ScriptEngine      更新时间:2023-09-26

我有一个桌面Java应用程序,它本质上是多个线程的调度器。每个线程负责读取JavaScript文件并解释/评估JavaScript代码。JavaScript为无限期运行的复杂任务编写脚本,控制由父Java应用程序公开的Java对象。

我对这些都没有意见。我创建了一个线程来读取适当的JavaScript文件,然后对其进行评估

public class TaskThread extends Thread {
    ...
    public void run() {
        String theScriptCode = ReadMyJavascriptFileIntoAString("somescript.js");
        ScriptEngineManager engineManager = new ScriptEngineManager();
        engine = engineManager.getEngineByName("nashorn");
        scriptableObject = new MyScriptableObjectClass();
        engine.put("scriptableObject", scriptableObject);
        engine.eval(theScriptCode);
    }
    ...
}

somescript.js文件可能包含以下内容:

while (!isAFullMoon()) {
    scriptableObject.doSomething();
    scriptableObject.doSomethingElse();
}

因此,该行:

engine.eval(theScriptCode);

可以很好地运行很长一段时间。

我需要的是,每当在ScriptCode中计算新的表达式/函数时,都会以某种方式通知我的TaskThread对象。这是必要的,因为engine.eval(ScriptCode)将运行很长一段时间,所以我希望ScriptEngine定期生成。

我可以通过使TaskThread对象对MyScriptableObjectClass()的实例可见来实现这一点。类似于:

        ...
        scriptableObject = new MyScriptableObjectClass(this);
        engine.put("scriptableObject", scriptableObject);
        ...

然后,在MyScriptableObjectClass的定义中:

public class MyScriptableObjectClass {
    private TaskThread parentThread;
    public MyScriptableObjectClass(TaskThread t) {
        this.parentThread = t;
    }
    public void doSomething() {
        // do something
        parentThread.yield();
        ...
    }
    public void doSomethingElse() {
        // do something else
        parentThread.yield();
        ...
    }

似乎必须有一种更优雅的方法来做到这一点——尤其是因为这只允许我在调用Java对象的方法时屈服。可能有相当长的一段时间,JavaScript在不调用任何Java对象成员的情况下执行。

我希望能够做一些事情,比如向ScriptEngine对象添加一个监听器,以便在每次计算新表达式时激发它。看起来这应该很直接,但我已经在这上面转了好几天了。

有什么想法吗?

nashorn不支持(nashorn编译的)脚本的这种"插入"。您可以实例化一个Timer或从脚本中派生一个单独的线程,并且定时器回调或线程的运行可以通过调用Java来"ping"脚本。