【问题标题】:Invoke JavaScript callback from a Java method asynchronously using Rhino使用 Rhino 从 Java 方法异步调用 JavaScript 回调
【发布时间】:2014-06-13 06:04:53
【问题描述】:

假设我有这样的脚本:

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,所以我需要以某种方式“取回”旧上下文(或者以其他方式存储它以供以后使用)。

我该怎么做呢?

【问题讨论】:

    标签: java javascript asynchronous closures rhino


    【解决方案1】:

    您可以采用很多方法,但我推荐的方法是为了最大限度地提高每一侧的代码的清洁度和清晰度。

    我假设 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 语法会变得更加复杂和混乱。

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

    请注意,resultreason 在这种情况下将是 java.lang.String 对象,而不是原生 JavaScript 字符串。在您的代码中没有区别,但如果您以后需要将它们用作 JavaScript 字符串,您可能希望使用 String(result)String(failure) 转换它们。

    【讨论】:

    • 这不是我想要的,因为它缺少“异步”组件。在这个解决方案中,调用线程(以及 Rhino 执行)将阻塞,直到 execute() 调用其中一个处理程序并返回,而不管 execute() 实际如何工作。在我的特殊情况下,我需要释放调用线程,然后再恢复,可能在另一个线程上。我一直在查看 Rhino 对延续的支持,这似乎提供了我正在寻找的东西。
    • 让我稍微修改一下我的问题。对于延续,我想我会在我的 API 中采用不同的方法。它看起来像一个正常的值返回函数,而不是一个将成功/失败回调作为参数的函数。回调样式仍然可以使用延续,但它不必要地更复杂。
    • 我改变了重新处理问题的想法,因为它使您的答案完全无关紧要。我已将其保留为原始形式,但我仍在寻找异步答案。我可能会在这周的某个时间解决它并发布我的结果,如果没有其他人可以解决它。
    • 抱歉,这是为了涵盖异步情况,在这些代码 cmets 的部分中:“省略实现;使用您想要使用的任何多线程策略”和“调用侦听器的成功/失败方法根据发生的情况,有适当的论据。”我已经填写了一点,以使其更清楚。我认为它满足您的需求。
    • 不错,出于这个问题的目的,我会接受它。也就是说,我仍然倾向于继续的原因是上面的 js 代码需要直接调用 Java 类,这在我的场景中是不可接受的。 Continuations 启用了非阻塞的返回值语义而不是非阻塞的基于回调的语义,让 js 用户无需直接使用 Java 类即可编写“正常”代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    • 2013-01-26
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多