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

时间:2014-04-27 20:14:27

标签: 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: " + reason; }
  });
  println("Starting to execute stuff...");
}

我们假设stuffExecutor是一个Java对象,它具有execute()方法,并且具有我已经放入上下文的相应签名。

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

我将如何做到这一点?

1 个答案:

答案 0 :(得分:0)

您可以采取许多方法,但我建议这样做是为了最大程度地保持清洁和每侧代码的清晰度。

我假设successfailure是字符串,但如果它们是其他的话,转换很简单。

在Java方面,制作您的API:

public class StuffExecutor {
  public abstract static class Listener {
    public abstract void success(String result);
    public abstract void failure(String reason);
  }

  private void stuff(Listener listener) {
    try {
      String result = doIt();
      listener.success(result);
    } catch (Throwable t) {
      listener.failure(t.getMessage());
    }
  }

  public void execute(final Listener listener) {
    new Thread(new Runnable() {
      public void run() {
        stuff(listener);
      }
    }).start();
  }
}

现在在JavaScript方面:

function hello() {
  var x = 42; // notice the closure over x in the success handler
  stuffExecutor.execute(new JavaAdapter(Packages.my.package.StuffExecutor.Listener, {
    success: function (result) { println("Success: " + (result + x)); },
    failure: function (reason) { println("Failure: " + reason; }
  }));
  println("Starting to execute stuff...");
}

就像我说的,其他方法可行。您可以将函数直接传递给Java API(它们将显示为org.mozilla.javascript.Callable),但是用于调用它们的Java语法会变得更加复杂和混乱。

请注意,1.7R4版本中的JavaAdapter存在一个错误(导致许多人要求1.7R5尚未发布)。这应该适用于任何其他版本的Rhino或GitHub上的当前版本。

请注意,resultreason在此方案中为java.lang.String个对象,而非本机JavaScript字符串。在您的代码中,它没有区别,但如果您以后需要将它们用作JavaScript字符串,则可能需要使用String(result)String(failure)转换它们。