用 Rhino 在 Java 中解释 JavaScript:暂停/恢复脚本

2022-09-03 08:04:41

我正在使用JDK的javax.script.*包。具体来说,我使用的是JavaScript引擎,从我所读到的内容来看,它似乎基于Mozilla开发的JavaScript-in-Java解释器Rhino。

我希望实现的是,基本上让我的JavaScript能够在代码中的某个点“暂停”自己(例如,函数调用的中途),并且只有在Java允许时才恢复自己。

为了说明我的意思,想象一下这个JavaScript代码:

function myJSFunction() {
    print("Hello ");
    mysteriousPauseFunction(); // this is the part I'm wondering about.  basically, the script should break here and resume later at Java's discretion...
    // upon reaching this comment, we know now that Java has told JavaScript that it's okay to resume, so the next line will now be executed...
    print("world");
}

如果“暂停”/“中断”部分涉及绑定Java函数并将其传递给当前ScriptEngine的引用或其他任何内容,那对我来说很酷。我想这可能就是:从Java内部暂停JavaScript。

我做了一些谷歌搜索,发现这里的关键词似乎是“延续”。据我所知,Rhino只支持解释模式(与编译模式相比)的延续,我看到这是通过将“上下文”设置为-2来完成的。由于内置的JDK ScriptEngine似乎没有提到任何关于上下文的内容(或者也许我错过了它),这是否意味着我必须直接下载和使用Mozilla的Rhino库?

犀牛的延续是我需要的吗?我找到了一个关于Rhino延续的有用教程,但是在通读它之后,我不能100%确定这是否能够完成我上面描述的事情。如果这就是我要查找的内容,那么我的后续问题是关于提到的“序列化”:这是否意味着当我恢复脚本时,除非我序列化它们,否则所有变量都将被取消设置?

更新:看起来这在犀牛身上是可能的。以下是我迄今为止在JavaScript中所拥有的内容;在代码之后,我将解释它的作用...

var end = new Continuation();

function myJSFunction()
{
    print("Hello ");
    var kont = new Continuation();
    storePause(script, kont); // script is previously bound by Java into the JavaScript.  it is a reference to the script itself.
    end();
    print("world");

}

我的“storePause()”函数是我写的Java函数,它绑定到JavaScript,但现在,它什么都不做。我的下一个目标是充实其代码,以便它将延续和脚本信息存储为Java对象,以便Java以后可以恢复脚本。

现在,它正在做的是暂停/“打破”脚本,在“Hello”打印之后,但在“世界”被打印之前,所以这向我证明,以这种方式暂停脚本是可能的。

因此,在这一点上,我应该弄清楚的是如何恢复延续。请注意,默认情况下,上述内容使用JDK脚本引擎工作(此时我不需要担心解释模式与编译模式 - 它似乎默认为解释模式),但看起来恢复脚本的过程将需要Mozilla的Rhino库。


答案 1

好吧,我花了很多时间挖掘文档,教程和示例,并在这里和Rhino Google Group上发布,但我已经设法编译了一个有效的解决方案。由于似乎没有完整的示例,因此我将在这里发布我的发现,以供将来偶然发现此内容的任何人使用。

实际上,我的发现可能太长而无法在这里发布,所以我决定在我的博客上写一个教程:

Tutorial: Continues in Mozilla Rhino (Java的JavaScript解释器)

希望能帮助别人。据我所知,这是唯一一个完整的 Rhino 教程,展示了如何执行以下所有操作:初始化 Rhino,从 JavaScript (*.js) 文件加载脚本,自动将特定 Java 类(例如 ScriptFunctions)中的所有函数绑定为 JavaScript 中的全局函数,最后调用 JavaScript 函数并处理该调用的延续。

基本上,问题是我需要首先下载Mozilla Rhino源代码(因为与JDK打包的版本已经过时并且不支持延续),重写我的所有代码以使用官方Rhino包的语法(它与JDK的ScriptingEngine语法非常不同),编写一个Java函数,该函数会抛出一个 ContinuationPending异常并将其绑定到JavaScript,以便JavaScript可以调用它(因为直接从JavaScript抛出一个CondutivePending)。 导致一个JavaScriptException被抛出,而不是一个 ContinuationPending 被抛出,甚至试图在该 JavaScriptException 上调用 getCause() 导致 null),然后在我的 Java 代码中调用我的 JavaScript 函数(在我原来的示例中为“myJSFunction”),尝试/捕获块来检查 ContinuationPending(这是一个例外),然后稍后使用该 ContinuationPending 来恢复脚本。

唷。这很艰难,但现在一切都是值得的。


答案 2

你没有解释为什么你这样做,但我正在模拟一个与最终用户交互的程序,如下所示:

print('Hello!'); 
a=Number(input('enter a number')); 
b=Number(input('and another number')); 
print('the sum of '+a+' plus '+b+' is '+(a+b))

我只是通过在javascript中创建一个打印和一个检查程序状态的输入函数来让它工作。

你可以在这里看到一个演示。

它都是用javascript编写的,所以你可以用任何浏览器查看源代码。

希望它有帮助