You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:35:33