3

我有一个向我发送大量 DTO 的服务器端服务。我需要将它们放在 CellTable 中。这就像 10-200 行,我需要同时查看所有内容。

我有一个服务器端日志,它跟踪我的服务的最后一个“人造”代码行(就在返回之前)。

最好的情况是,此日志与完全加载的表之间有 2 分钟的差距。大多数时候,在这个过程中有些东西会中断,这让我悬而未决。

我有什么选择?

谢谢

编辑:我尝试了 Andrei 的想法,区分数据下载的长度(rpc 回调)和 celltable 加载的长度。

我想确定一下,这就是我在回调中所做的:

@Override
public void onSuccess(ResponseBean result) {
  Window.alert("success " + new Date().toString());

  resultPanel.updateResults(result);

  Window.alert("celltable " + new Date().toString());
}

第一个警报发生在约 10 秒后。但是第二个永远不会被调用。

这是 updateResults 背后的方法:

public void updateResults(ResponseBean response) {
  dataProvider.getList().clear();
  dataProvider.getList().addAll(response.beans());
  myCellTable.setPageSize(response.beans.size());
}

编辑2:我尝试了很多东西。当我尝试用我的数据填充单元格表时会出现问题。在 Chrome 中,出现了 BSOD 的 chrome 版本。在 Firefox 中,它会静默中断,但不会执行剩余的 js 指令。如果我尝试在 firebug 中读取控制台,我的 firefox 会使用 ~2.5GB ram 冻结。如果我使用 gwt-runner,它也会冻结。

在我的示例中,只有 4 行(4 个具有多个依赖项的对象)!

我怎样才能找到什么中断和在哪里?

感谢您的帮助:)

最后:好的,所以我显然是个白痴。在 getValues() 的某个地方,有一段“业务逻辑”不应该存在,这导致了 OutOfMemory 错误。

外卖虽然:

  • 跟踪最后一次调用server-side和onSuccess client-side的第一行,看问题是否与RPC有关
  • 如果您的单元格表中断但只有几行,那么您做了一些您不会引以为豪的事情
  • Scheduler.get().scheduleDeffered 允许您渲染页面,然后执行您的业务逻辑。所以这很酷。

多谢你们

4

2 回答 2

3

通常我会把钱押在 RPC 序列化是瓶颈而不是CellTable渲染上。
但是,您说第一个警报会在 10 秒后出现,这会反对。

使用 . 渲染 200 个 DTO 应该足够快CellTable
此外,通过网络发送 200 个 DTO 应该没问题。

我已经使用CellTable并通过网络发送了大约 5000 个 DTO,没有任何性能问题(尽管我一次只显示 50 个并使用分页)。

几个想法:

  • 开发模式比生产模式慢得多(尤其是在反序列化方面)。因此也在生产模式下测试性能。
  • 要找出究竟是什么导致了您的问题,请使用 Chrome 开发工具。您可以分析您的代码并查看导致延迟的原因。
  • 您能否在代码中手动创建 200 个虚拟 DTO 并将其传递给您的updateResults函数并查看性能比较。
  • 你显示多少列?如果您显示许多列,请将其减少到仅一列,看看它如何影响性能。
  • CellTable 列中使用的任何 getter 是否具有昂贵的业务逻辑?
于 2012-09-26T08:13:34.310 回答
1

对于这么多数据,您应该使用寻呼机和 AsyncDataProvider。这是我们如何做到这一点的模板。它可能无法满足您的需求,但它会给您一个起点。DatastoreObjectProxy 从 EntityProxy 扩展而来,并使用请求工厂来获取项目。您可以将您的表添加到此数据提供程序中,并且寻呼机将处理获取您的数据块。

public abstract class DaoBaseDataProvider<T extends DatastoreObjectProxy> extends AsyncDataProvider<T> implements SearchProvider<T> {

    public static final ProvidesKey<DatastoreObjectProxy> KeyProvider = new ProvidesKey<DatastoreObjectProxy>() {

        @Override
        public Long getKey(DatastoreObjectProxy item) {
            return item.getId();
        }
    };

    public interface HasBaseDataProvider<T extends DatastoreObjectProxy> {
        public void setDataProvider(DaoBaseDataProvider<T> dataProvider);

        public void setSelectionModel(SelectionModel<? super T> selectionModel);
    }

    public DaoBaseDataProvider() {
        super(new ProvidesKey<T>() {
            public Long getKey(T item) {
                // Always do a null check.
                return (item == null) ? null : item.getId();
            }
        });
    }

    @Override
    public void search(String searchText) {

        getSearchQuery(searchText).fire(new Receiver<List<T>>() {

            @Override
            public void onSuccess(List<T> values) {
                updateRowData(0, values);
                updateRowCount(values.size(), true);
            }
        });
    }

    public void showAll() {
        updateRowCount(10, false);
    }

    @Override
    protected void onRangeChanged(HasData<T> display) {
        final Range range = display.getVisibleRange();

        Request<List<T>> request = getRangeQuery(range);
        if (getWithProperties() != null) {
            request.with(getWithProperties());
        }

        request.fire(new Receiver<List<T>>() {

            @Override
            public void onSuccess(List<T> values) {
                updateRowData(range.getStart(), values);
            }
        });
    }

    public abstract String[] getWithProperties();

    public abstract DaoRequest<T> getRequestProvider();

    public void remove(final Set<Long> idsToDelete) {
        getDeleteQuery(idsToDelete).fire(new Receiver<Integer>() {

            @Override
            public void onSuccess(Integer response) {
                for (HasData<T> display : getDataDisplays()) {
                    // Force the display to relaod it's view.
                    display.setVisibleRangeAndClearData(display.getVisibleRange(), true);
                }
            }
        });
    }

    /**
     * This can be overridden so that you can change the query.
     * 
     * @param range
     * @return
     */
    protected Request<List<T>> getRangeQuery(Range range) {
        Request<List<T>> request = getRequestProvider().findRange(range.getStart(), range.getLength());
        if (getWithProperties() != null) {
            request.with(getWithProperties());
        }
        return request;
    }

    protected Request<List<T>> getSearchQuery(String searchText) {
        Request<List<T>> request = getRequestProvider().search(searchText).with(getWithProperties());
        if (getWithProperties() != null) {
            request.with(getWithProperties());
        }
        return request;

    }

    protected Request<Integer> getDeleteQuery(Set<Long> idsToDelete) {
        return getRequestProvider().deleteList(idsToDelete);
    }
}

这是用于获取对象的客户端类。您可以使用自己的 RequestContext 扩展它。

public interface DaoRequestFactory extends RequestFactory {

    @Service(value = DaoBase.class, locator = DaoServiceLocator.class)
    public interface DaoRequest<T extends DatastoreObjectProxy> extends RequestContext {

        Request<T> find(Long id);

        Request<List<T>> findRange(int start, int end);

        Request<Integer> deleteList(Set<Long> idsToDelete);

        Request<List<T>> search(String searchText);

        Request<Long> save(T obj);

        Request<Void> delete(Long objId);
    }
}
于 2012-09-25T22:20:10.313 回答