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 框架是按以下方式处理请求的:
- 处理从客户端发送的任何更改
- 呼叫您的听众(ValueChange、Click、...)
- 向客户端发送更改
当第一个线程处于第三步时第二个线程更改 URL 时,这可能会导致严重的问题,因为只有一半的更改会传输到客户端。 Vaadin 在检测到 an 告诉您使用 UI.access(...) 时抛出异常。 UI.access() 负责直接执行提供的 Runnable(当没有处理其他请求时)或在当前 运行 请求完成后异步执行。
最后一张纸条。锁定是基于会话的,而不仅仅是基于 UI。因此,对同一会话中不同 UI 的更改(例如,同一应用程序的不同选项卡)也会按顺序处理。
我正在尝试在 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 框架是按以下方式处理请求的:
- 处理从客户端发送的任何更改
- 呼叫您的听众(ValueChange、Click、...)
- 向客户端发送更改
当第一个线程处于第三步时第二个线程更改 URL 时,这可能会导致严重的问题,因为只有一半的更改会传输到客户端。 Vaadin 在检测到 an 告诉您使用 UI.access(...) 时抛出异常。 UI.access() 负责直接执行提供的 Runnable(当没有处理其他请求时)或在当前 运行 请求完成后异步执行。 最后一张纸条。锁定是基于会话的,而不仅仅是基于 UI。因此,对同一会话中不同 UI 的更改(例如,同一应用程序的不同选项卡)也会按顺序处理。