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

Vaadin Grid启用Push后内容未按预期异步加载问题求助

Vaadin Grid 异步加载内容未逐个刷新的问题

我在使用开启Push功能的Vaadin Grid,预期实现:实体已有的数据立即加载,异步方法获取的数据通过回调逐个更新到网格中。但目前网格框架能立即显示,所有内容却要等待较长时间后一次性加载完成。

原代码示例

Grid 初始化代码

private void setupGrid() {
  // String grid for illustration
  Grid<String> grid = new Grid<>();
  grid.addComponentColumn(this::getIconColumn).setHeader("Name");

  // other entity items would be displayed here
  // grid.addComponentColumn(this::getMainColumn).setHeader("Other");

  grid.setItems("2800-player-who-returned-10000-years-later",
    "2633-duke-pendragon", "8713-dungeon-reset");

  // this allows the outer grid structure to be displayed while not blocking UI
  // but content is still loaded "synchronously" - all at once, not one by one
  grid.getDataCommunicator().enablePushUpdates(Executors.newCachedThreadPool());

  add(grid);
}

组件列异步加载方法

private Image getIconColumn(String entityName) {
  Image image = new Image("", "");
  image.setHeight("150px");
  image.setWidth("100px");

  UI ui = UI.getCurrent();
  asyncLoadIcon(entityName)
      .addCallback(
          result -> ui.access(() -> image.setSrc(result)),
          err -> ui.access(() -> Notification.show("Failed to parse icon for " + entityName))
      );

  return image;
}

异步加载工具方法

@Async
public ListenableFuture<String> asyncLoadIcon(String entityName) {
  try {
    // some real code

    Thread.sleep(3000);
    return AsyncResult.forValue(entityname);

  } catch (IOException | InterruptedException e) {
    log.error(e);
  }
  return AsyncResult.forExecutionException(new RuntimeException("Error"));
}

问题原因

  1. enablePushUpdates仅作用于Grid数据通信器的后台数据处理,对组件列内部单个组件的异步更新无直接效果。
  2. Vaadin默认会合并UI.access中的更新操作,延迟推送,导致所有异步任务完成后一次性刷新界面。
  3. 异步方法存在拼写错误:entityname应改为entityName,会导致返回无效结果。

解决方案

1. 确保Vaadin Push配置正确

在Spring Boot项目的application.properties中添加:

vaadin.push.enabled=true
vaadin.push.mode=automatic

2. 修改组件列更新逻辑,手动触发推送

在UI.access中更新组件后,调用ui.push()强制立即推送更新,避免批量合并:

private Image getIconColumn(String entityName) {
  Image image = new Image("", "");
  image.setHeight("150px");
  image.setWidth("100px");

  UI ui = UI.getCurrent();
  asyncLoadIcon(entityName)
      .addCallback(
          result -> ui.access(() -> {
              image.setSrc(result);
              // 手动触发推送,确保单个组件更新立即生效
              ui.push();
          }),
          err -> ui.access(() -> {
              Notification.show("Failed to parse icon for " + entityName);
              ui.push();
          })
      );

  return image;
}

3. 修正异步方法的拼写错误

@Async
public ListenableFuture<String> asyncLoadIcon(String entityName) {
  try {
    // 实际业务代码

    Thread.sleep(3000);
    return AsyncResult.forValue(entityName); // 修正变量名拼写

  } catch (IOException | InterruptedException e) {
    log.error("加载图标失败", e);
  }
  return AsyncResult.forExecutionException(new RuntimeException("Error"));
}

4. 优化线程池配置

避免使用无界的CachedThreadPool,改用有界线程池控制并发数,防止资源耗尽:

grid.getDataCommunicator().enablePushUpdates(Executors.newFixedThreadPool(5));

内容的提问来源于stack exchange,提问作者Michael Kročka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:15:53