Gwt性能问题:巨大的数据和celltable

时间:2012-09-25 14:43:26

标签: gwt gwt-celltable

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

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

最好的情况是,这个日志和满载的表之间有2分钟的差距。大多数时候,某些事情会在整个过程中出现问题,而这让我感到不知所措。

我有什么选择?

由于

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

我想确定这就是我在回调中所做的事情:

@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: 我尝试过很多东西。当我尝试用我的数据填充celltable时,会出现问题。 在Chrome中,会显示BSOD的Chrome版本。在Firefox中,它会以静默方式中断,但其余的js指令不会被执行。 如果我尝试在firebug中读取控制台,我的firefox使用~2.5GB ram冻结。如果我使用gwt-runner,它也会冻结。

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

我怎样才能找到WHAT休息和哪里?

感谢您的帮助:)

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

尽管如此:

  • 跟踪服务器端的最后一个呼叫和onSuccess客户端的第一行,以查看问题是否与RPC相关
  • 如果您的细胞表中断但只有几行,那么您做了一些您不会为之自豪的事情
  • Scheduler.get()。scheduleDeffered允许您呈现页面,然后执行业务逻辑。这太酷了。

谢谢你们

2 个答案:

答案 0 :(得分:3)

通常我会打赌我的RPC序列化是瓶颈而不是CellTable渲染。
但是你说第一个警报出现在10秒之后会反对。

使用CellTable渲染200 DTO应该足够快 通过电线发送200 DTO应该不是问题。

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

有几点想法:

  • 开发模式比生产模式慢得多(特别是关于反序列化)。因此,测试性能也在生产模式下。
  • 要了解导致问题的原因,请使用Chrome开发工具。您可以分析代码并查看导致延迟的原因。
  • 您可以在代码中手动创建200个Dummy DTO并将其传递给updateResults函数,并查看性能的比较情况。
  • 您展示了多少列?如果显示多列,请将其减少为一列,并查看它对性能的影响。
  • 在CellTable列中使用的任何getter是否都有昂贵的业务逻辑?

答案 1 :(得分: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);
    }
}