使用Rhino从Java方法异步调用JavaScript回调

使用Rhino从Java方法异步调用JavaScript回调,java,javascript,asynchronous,closures,rhino,Java,Javascript,Asynchronous,Closures,Rhino,假设我有这样一个脚本: function hello() { var x = 42; // notice the closure over x in the success handler stuffExecutor.execute({ success: function (result) { println("Success: " + (result + x)); }, failure: function (reason) { println("Failure: " +

假设我有这样一个脚本:

function hello() {
  var x = 42; // notice the closure over x in the success handler
  stuffExecutor.execute({
    success: function (result) { println("Success: " + (result + x)); },
    failure: function (reason) { println("Failure: " + reason; }
  });
  println("Starting to execute stuff...");
}
让我们假设
stuffExecutor
是一个Java对象,它有一个
execute()
方法,该方法具有我在上下文中输入的适当签名

我可以想象实现
execute()
方法将其操作延迟到
hello()
脚本返回之后(从而在成功或失败之前先打印“开始执行东西…”),但从那里我不知道如何返回并在延迟执行完成后调用处理程序。特别是,
success
处理程序通过
hello()
函数关闭局部变量
x
,因此我需要以某种方式“返回”旧上下文(或者存储它以备以后使用)


我该怎么做呢?

您可以采取很多方法,但为了最大程度地保持代码的清洁和清晰,我推荐以下方法

我假设
success
failure
都是字符串,但如果它们是其他字符串,则转换是直接的

在Java方面,使您的API:

公共类StuffExecutor{
公共抽象静态类侦听器{
公开摘要作废成功(字符串结果);
公共摘要无效失败(字符串原因);
}
私有void内容(侦听器){
试一试{
字符串结果=doIt();
成功(结果);
}捕获(可丢弃的t){
失败(t.getMessage());
}
}
public void execute(最终侦听器){
新线程(newrunnable()){
公开募捐{
材料(听众);
}
}).start();
}
}
现在在JavaScript方面:

函数hello(){ var x=42;//注意成功处理程序中x上的闭包 execute(新的JavaAdapter(Packages.my.package.stuffExecutor.Listener{ success:function(result){println(“success:+(result+x));}, 失败:函数(原因){println(“失败:+reason;} })); println(“开始执行东西…”); } 正如我所说,其他方法也可以起作用。您可以将函数直接传递给Java API(它们将显示为
org.mozilla.javascript.Callable
),但是调用它们的Java语法会变得更加复杂和混乱

请注意,1.7R4版本中的JavaAdapter中有一个bug(这导致许多人争相购买尚未上市的1.7R5)。这应该适用于Rhino的任何其他版本或GitHub上的当前主版本


请注意,
result
reason
将是本场景中的
java.lang.String
对象,而不是本机JavaScript字符串。在您的代码中,这没有什么区别,但如果您以后需要将它们用作JavaScript字符串,您可能希望使用
String(result)
String(失败)来转换它们

这不是我想要的,因为它缺少“异步”组件。在这个解决方案中,调用线程(以及Rhino执行)将阻塞,直到
execute()
调用其中一个处理程序并返回,而不管
execute()如何
实际上是起作用的。在我的特殊情况下,我需要释放调用线程,然后稍后在另一个线程上恢复。我一直在研究Rhino对continuations的支持,这似乎提供了我所需要的。让我实际修改一下我的问题。有了continuations,我想我会选择d在我的API中有不同的方法。它看起来像一个普通的值返回函数,而不是一个以成功/失败回调为参数的函数。回调样式仍然可以使用continuations,但它不必要地更复杂。我改变了对重新处理问题的想法,因为这样会使你的答案完全不相关。我离开了它以其原始形式出现,但我仍在寻找异步答案。如果没有其他人关注它,我可能会在本周某个时候解决它并发布我的结果。抱歉,这是为了涵盖异步情况,在包含以下代码注释的部分中:“省略实现;使用您想要使用的任何多线程策略”和“根据发生的情况使用适当的参数调用侦听器的成功/失败方法”。"为了让它更清楚,我已经补充了一些内容。我认为它满足了您的需求。不错,出于这个问题的目的,我会接受它。也就是说,我仍然倾向于使用continuations的原因是,上面的js代码需要直接调用Java类,这在我的场景中是不可接受的。continuations支持非阻塞return值语义,而不是基于非阻塞回调的语义,允许js用户编写“普通”代码,而无需直接使用Java类。