Vaadin中能否用XHR替代Push实现带进度条的UI异步更新?
Vaadin纯XHR异步UI更新实现方案
完全可以不依赖Push机制,仅通过Vaadin原生的XHR(UIDL请求)实现你要的异步UI更新效果,把Push留作被动通知场景使用。以下是具体实现思路和代码示例:
核心原理
Vaadin的客户端与服务器通信本身就是基于/?v-r=uidl&v-uiId=xxx格式的XHR请求同步UI状态。我们可以通过客户端主动触发UIDL请求的方式,替代Push的主动推送,实现进度条的显示与隐藏逻辑。
实现方式
方案1:强制触发UIDL请求(无轮询)
这种方式不需要客户端持续轮询,而是在需要更新UI时,主动让客户端发送一次UIDL请求获取最新状态:
@Push(Mode.DISABLED) // 完全禁用Push,仅保留XHR通信 public class TaskView extends VerticalLayout { private final ProgressBar progressBar; public TaskView() { // 初始化进度条,默认隐藏 progressBar = new ProgressBar(); progressBar.setIndeterminate(true); progressBar.setVisible(false); add(progressBar); // 触发任务的按钮 Button startBtn = new Button("启动耗时任务", e -> startAsyncTask()); add(startBtn); } private void startAsyncTask() { // 1. 立即显示进度条,标记UI状态变更 progressBar.setVisible(true); UI.getCurrent().getInternals().setPendingStateChange(true); // 强制客户端发送UIDL请求,同步进度条显示状态 UI.getCurrent().getPage().executeJs("vaadin.forceUidlRequest()"); // 2. 启动异步耗时任务 CompletableFuture.runAsync(() -> { // 模拟耗时操作(比如业务逻辑处理) try { Thread.sleep(5000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } // 3. 任务完成后更新UI状态 UI.getCurrent().access(() -> { progressBar.setVisible(false); UI.getCurrent().getInternals().setPendingStateChange(true); // 再次强制客户端发送UIDL请求,同步进度条隐藏状态 UI.getCurrent().getPage().executeJs("vaadin.forceUidlRequest()"); }); }); } }
方案2:客户端轮询(适合长期后台任务)
如果任务执行时间不确定,也可以设置客户端定期轮询UIDL请求,自动获取UI更新:
@Push(Mode.DISABLED) public class PollingTaskView extends VerticalLayout { private final ProgressBar progressBar; public PollingTaskView() { progressBar = new ProgressBar(); progressBar.setIndeterminate(true); progressBar.setVisible(false); add(progressBar); Button startBtn = new Button("启动任务", e -> startPollingTask()); add(startBtn); } private void startPollingTask() { progressBar.setVisible(true); // 设置客户端每500ms发送一次UIDL请求 UI.getCurrent().setPollInterval(500); CompletableFuture.runAsync(() -> { // 模拟耗时操作 try { Thread.sleep(5000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } UI.getCurrent().access(() -> { progressBar.setVisible(false); // 任务完成后取消轮询 UI.getCurrent().setPollInterval(-1); }); }); } }
关键细节说明
vaadin.forceUidlRequest():Vaadin客户端内置方法,会主动发送/?v-r=uidl&v-uiId=xxx格式的XHR请求,获取最新UI状态,完全符合你的需求。UI.getCurrent().getInternals().setPendingStateChange(true):标记UI状态已变更,确保服务器会在UIDL请求中返回更新后的状态。UI.access():在异步线程中安全更新UI的标准方式,会将更新逻辑提交到UI线程执行,避免线程安全问题。
内容的提问来源于stack exchange,提问作者alexanoid
相关产品推荐
相关产品推荐

