Vaadin javascript 扩展中的并行 AJAX 调用

Parallel AJAX calls in Vaadin javascript extension

我正在尝试在 java 脚本中编写一个简单的 Vaadin 扩展(意思是我 subclass AbstractJavaScriptExtension),它会触发服务器端的方法调用。此方法调用将例如加载一些数据并更新组件的 UI。基本上,这个想法是对每个组件进行单次异步请求,目标是在服务器端 运行 并行进行潜在的长 运行ning 数据库/网络服务调用。

因为我不需要持续更新组件,所以使用 Vaadin Push 就有点过分了。我想使用普通的旧 XHR。

所以我在我的扩展 class 中添加了一个 java 脚本触发函数,如下所示:

addFunction("trigger", jsonArray -> command.trigger());

(这是 java 8 语法,trigger() 只是功能接口上的一个方法)

我尝试在我的 java 脚本连接器中立即调用此触发器,如下所示:

window.com_example_AsyncTrigger = function () {
    this.trigger();
}

我编写了一个虚拟组件,使用 Thread.sleep() 模拟缓慢加载并创建了三个实例,延迟分别为 10 秒、6 秒和 2 秒,同时记录加载的开始和结束时间戳。 然后我用我的扩展扩展了三个布局,以在触发相应触发器时将每个组件添加到其中。

当然,所有三个触发器都被触发了,但它们是在同一个请求中触发的(我可以从日志记录中看出它们是在单个服务器线程中执行的)。这意味着大约 18 秒后,所有 3 个组件都会立即更新,而我希望首先显示 2 秒的组件,然后是 6 秒的组件,最后是 10 秒的组件,总时间约为 10 秒。

所以,我想这一定是因为 Vaadin 在创建连接包装器时以某种方式将完成的函数调用排队,并在单个请求上调用服务器端方法。所以我更改了 javascript 连接器实现以异步调用客户端 trigger() 函数,如下所示:

window.com_example_AsyncTrigger = function () {
    var self = this;
    setTimeout(function() { self.trigger();}, 0);
}

当然,这些触发器现在会在单独的请求中触发,正如我从日志中可以看出工作线程的名称不同一样。 唯一的问题是......他们仍然运行顺序。对 self.trigger() 的调用是快速连续完成的,但实际的 XHR 请求并不是并行完成的。下一个只有在上一个完成后才开始。

为什么会这样,我该如何解决?

网络服务器不会并行处理来自同一客户端的请求,以防止出现任何竞争条件或锁定问题。要处理长 运行 请求,您需要与处理请求的线程异步执行。完成后,使用 UI.access(...) 将结果写回 UI。处理请求的线程将 return 并处理下一个请求。问题是在客户端发送下一个请求之前,结果不会发送到服务器。但是所有长 运行 请求都是并行处理的。

第一个选项:

定期轮询服务器(有一个 vaadin 插件)。结果将与下一次投票一起发送。

第二个选项:

不用轮询,只需使用推送。开销不是那么大,如果您不希望同时有数百个用户,那应该不是问题。

进一步说明:

据我了解,Vaadin 框架是按以下方式处理请求的:

  1. 处理从客户端发送的任何更改
  2. 呼叫您的听众(ValueChange、Click、...)
  3. 向客户端发送更改

当第一个线程处于第三步时第二个线程更改 URL 时,这可能会导致严重的问题,因为只有一半的更改会传输到客户端。 Vaadin 在检测到 an 告诉您使用 UI.access(...) 时抛出异常。 UI.access() 负责直接执行提供的 Runnable(当没有处理其他请求时)或在当前 运行 请求完成后异步执行。 最后一张纸条。锁定是基于会话的,而不仅仅是基于 UI。因此,对同一会话中不同 UI 的更改(例如,同一应用程序的不同选项卡)也会按顺序处理。