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

Vaadin 23无需@PUSH实现异步加载占位内容的方案咨询

无@PUSH实现先显示进度条再异步加载Portlet内容

要解决iPhone上WebSocket失效的问题,同时保留「先显示进度条再加载内容」的交互,完全可以不用@PUSH,通过先推送进度条UI、再由客户端主动发起异步加载请求的方式实现,核心是拆分UIDL响应批次:

实现步骤

1. 先渲染进度条并强制刷到客户端

页面加载时,先把进度条添加到占位符,然后手动触发一次UIDL响应,让进度条单独发送到客户端显示:

// 视图初始化时的代码
ProgressBar progressBar = new ProgressBar();
progressBar.setIndeterminate(true);
placeholderLayout.add(progressBar);

// 强制刷新UI,让进度条先显示给用户
VaadinSession session = VaadinSession.getCurrent();
session.lock();
try {
    session.getCommunicationManager().flushUI(UI.getCurrent());
} finally {
    session.unlock();
}

这一步的关键是flushUI,它会把当前已有的UI变更单独打包成一个UIDL响应发送,不会等后续的内容加载完成再一起返回。

2. 客户端主动发起内容加载请求

进度条显示后,通过客户端JS触发服务器端的异步加载逻辑,全程由客户端发起XHR请求,无需服务器推送:

// 触发客户端调用服务器方法
UI.getCurrent().getPage().executeJs("$0.$server.loadPortletContent();", this);

// 服务器端的回调方法,处理异步加载
@ClientCallable
public void loadPortletContent() {
    // 用后台线程执行耗时的portlet加载逻辑,避免阻塞UI线程
    CompletableFuture.runAsync(() -> {
        // 模拟加载过程(替换为实际的portlet加载代码)
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 加载完成后更新UI,替换进度条为portlet内容
        UI.getCurrent().access(() -> {
            placeholderLayout.removeAll();
            // 添加实际的portlet组件,例如:
            placeholderLayout.add(new VerticalLayout(
                new H3("Portlet 内容已加载"),
                new Label("这里是Portlet的具体内容")
            ));
        });
    });
}

关键注意事项

  • 手动flushUI必须在VaadinSession锁定范围内执行,避免线程安全问题。
  • 内容加载逻辑必须放在后台线程,不能阻塞UI线程,否则会导致后续UI响应卡住。
  • 后台线程更新UI时,必须通过UI.access()方法确保在UI上下文内操作。

内容的提问来源于stack exchange,提问作者alexanoid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:20:34