简体   繁体   English

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

[英]Invoke JavaScript callback from a Java method asynchronously using Rhino

Suppose I have a script like so: 假设我有一个像这样的脚本:

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...");
}

Let's assume stuffExecutor is some Java object which has an execute() method with the appropriate signature that I've put into the context. 假设stuffExecutor是一些Java对象,它具有execute()方法,该方法具有我放入上下文中的适当签名。

I can imagine implementing the execute() method to defer its action until after the hello() script returns (thereby printing "Starting to execute stuff..." first before either succeeding or failing), but from there I don't know how to go back and invoke the handlers later, after the deferred execution completes. 我可以想象实现execute()方法以将其操作推迟到hello()脚本返回之后(从而在成功或失败之前先打印“正在开始执行...”),但是从那里我不知道如何在推迟执行完成后,返回并稍后调用处理程序。 In particular, the success handler closes over the local variable x from the hello() function, so I'd somehow need to "get back" the old context (or otherwise store it for later use). 特别是, success处理程序会从hello()函数关闭局部变量x ,因此我需要以某种方式“取回”旧上下文(或以其他方式存储以供以后使用)。

How would I go about doing this? 我将如何去做呢?

There are a lot of approaches you could take, but here is the one I'd recommend for maximum cleanliness and clarity of the code on each side. 您可以采用很多方法,但是我建议您使用这种方法,以最大程度地提高代码的清洁度和清晰度。

I'm assuming success and failure are strings, but the transformation is straightforward if they are something else. 我假设successfailure是字符串,但是如果它们是其他东西,则转换很简单。

On the Java side, make your API: 在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();
  }
}

Now on the JavaScript side: 现在在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...");
}

Like I said, other approaches could work. 就像我说的,其他方法也可以。 You could pass functions directly to your Java API (they will appear as org.mozilla.javascript.Callable ) but then your Java syntax for invoking them gets a lot more complex and messy. 您可以将函数直接传递给Java API(它们将显示为org.mozilla.javascript.Callable ),但是调用它们的Java语法变得更加复杂和混乱。

Note that there was a bug in JavaAdapter in the 1.7R4 release (which has caused many people to clamor for a 1.7R5 that has not come). 请注意,1.7R4发行版中的JavaAdapter中存在一个错误(这引起许多人争相购买尚未出现的1.7R5)。 This should work with any other release of Rhino or with the current master on GitHub. 这可以与任何其他Rhino版本或GitHub上的当前master一起使用。

Note that result and reason would be java.lang.String objects in this scenario, not native JavaScript strings. 请注意,在这种情况下, resultreason将是java.lang.String对象,而不是本机JavaScript字符串。 In your code it would make no difference but if you needed to use them later as JavaScript strings you'd probably want to convert them using String(result) and String(failure) . 在您的代码中没有什么区别,但是如果您以后需要将它们用作JavaScript字符串,则可能要使用String(result)String(failure)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM