首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为GWT RPC异步调用启用缓存

为GWT RPC异步调用启用缓存
EN

Stack Overflow用户
提问于 2012-07-30 10:14:57
回答 3查看 1.7K关注 0票数 2

我正在考虑引入某种缓存机制(比如HTML5本地存储),以尽可能避免频繁的RPC调用。我想得到关于如何在下面的代码中引入缓存的反馈,而不需要更改太多的体系结构(比如使用gwt-dispatch)。

代码语言:javascript
复制
void getData() {

    /* Loading indicator code skipped */

    /* Below is a gwt-maven plugin generated singleton for SomeServiceAsync */
    SomeServiceAsync.Util.getInstance().getDataBySearchCriteria(searchCriteria, new AsyncCallback<List<MyData>>() {

        public void onFailure(Throwable caught) {
            /* Loading indicator code skipped */
            Window.alert("Problem : " + caught.getMessage());
        }

        public void onSuccess(List<MyData> dataList) {
            /* Loading indicator code skipped */
        }
    });
}

我能想到的一种方法是用一个自定义的MyAsyncCallback类来定义onSuccess/onFailure方法,然后做如下的事情:

代码语言:javascript
复制
void getData() {

    AsyncCallback<List<MyData>> callback = new MyAsyncCallback<List<MyData>>;

    // Check if data is present in cache
    if(cacheIsPresent)
        callback.onSuccess(dataRetrievedFromCache);
    else
    //  Call RPC and same as above and of course, update cache wherever appropriate
}

除此之外,我还有一个问题。适用于流行浏览器的LocalStorage的最大可用存储大小是多少?浏览器如何管理不同应用程序/URL的LocalStorage?任何指针都将不胜感激。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-07-30 13:55:40

我建议添加一个处理缓存的delegate class。委托类可能如下所示:

代码语言:javascript
复制
public class Delegate {

  private static SomeServiceAsync service = SomeServiceAsync.Util.getInstance();

  private List<MyData> data;

  public static void getData(Callback callback) {
    if (date != null) {
      callback.onSuccess(data);
    } else {
      service.getData(new Callback() {
        public onSuccess(List<MyData> result) {
          data = result;
          callback.onSuccess(result);
      });
    }
  }

}

当然,这是一个粗糙的示例,您必须改进代码以使其可靠。

票数 2
EN

Stack Overflow用户

发布于 2012-07-30 14:05:12

我确实花了很长时间来决定是否使用散列映射来缓存结果。

我的策略不是使用单例hashmap,而是一个存储静态缓存实例的单例通用对象类。我看不出为什么要加载一个哈希树分支级别过高的单个哈希图。

减少散列解析的数量

如果我知道我正在处理的对象是Employee、Address、Project,我将创建三个静态散列

代码语言:javascript
复制
final static private Map<Long, Employee> employeeCache =
  new HashMap<Long, Employee>();
final static private Map<Long, Address> addressCache =
 new HashMap<Long, Address>();
final static private Map<String name, Project> projectCache =
 new HashMap<String name, Project>();

public static void putEmployee(Long id, Employee emp){
  employeeCache.put(id, emp);
}
public static Employee getEmployee(Long id){
  return employeeCache.get(id);
}

public static void putEmployee(Long id, Address addr){
  addressCache.put(id, addr);
}
public static Address getEmployee(Long id){
  return addressCache.get(id);
}

public static void putProject(String name, Address addr){
  projectCache.put(name, addr);
}
public static Address getProject(String name){
  return projectCache.get(name);
}

把所有这些都放在一张地图上是很麻烦的。有效访问和存储数据的原则是-您确定的关于数据的信息越多,您就越应该利用这些信息来隔离数据。这将降低访问数据所需的散列解析级别。更不用说需要进行的所有风险和不确定的类型转换了。

如果可以,请避免散列

如果您知道您总是只有一个值CurrentEmployee和NextEmployee,请避免将它们存储在Employee的散列中。只需创建静态实例

代码语言:javascript
复制
Employee CurrentEmployee, NextEmployee;

这将完全避免需要任何散列解析。

避免污染全局命名空间

如果可能,将它们保留为类实例,而不是静态实例,以避免污染全局命名空间。

为什么要避免污染全局名称空间呢?因为,由于全局名称空间的混乱,多个类可能会无意中使用相同的名称,从而导致数不清的bug。

将缓存保持在离预期或使用位置最近的位置

如果可能,如果缓存主要用于某个类,请将缓存保留为该类中的类实例。并为另一个类需要从该缓存中获取数据的任何罕见实例提供eventbus事件。

这样你就会有一个可预期的模式

代码语言:javascript
复制
ZZZManager.getZZZ(id);

在可能的情况下完成缓存

否则/并通过提供putter和getter将其私有化。不要允许另一个类无意中重新实例化缓存,特别是如果有一天您的类变成了一个通用的实用程序库。另外,putter和getter有机会验证请求,以避免请求清除缓存或将应用程序推入异常,方法是直接向缓存提供缓存无法处理的键或值。

将这些原则转换为Javascript本地存储

GWT页面上写着

明智地使用命名约定可以帮助处理存储数据。例如,在名为MyWebApp的web应用程序中,与名为MyWebApp的UI表中的行关联的键值数据的键名可以带有前缀MyWebApp.Stock。

因此,在您的类中使用相当粗糙的代码来补充HashMap,

代码语言:javascript
复制
public class EmployeePresenter {
  Storage empStore = Storage.getLocalStorageIfSupported();
  HashMap<Long, Employee> employeeCache;

  public EmployeePresenter(){
    if (empStore==null) {
      employeeCache = new HashMap<Employee>();
    }
  }

  private String getPrefix(){
    return this.getClass()+".Employee";
    //return this.getClass().getCanonicalName()+".Employee";
  }

  public Employee putEmployee(Long id, Employee employee)
    if (empStore==null) {
      stockStore.setItem(getPrefix()+id, jsonEncode(employee));
      return;
    }
    employeeCache.put(id, employee);
  }

  public Employee getEmployee(Long id)
    if (empStore==null) {
      return (Employee) jsonDecode(Employee.class, stockStore.getItem(getPrefix()+id));
    }
    return employeeCache(id);
  }
}

由于localstore仅基于字符串,因此我假定您将编写自己的json编码器解码器。另一方面,为什么不在从回调接收到json时将其直接写入到存储中呢?

内存约束-

我不能自称是这个问题的专家,但我预测hashmap的答案是浏览器上操作系统限制的最大内存。减去浏览器、插件和javascript等开销已经消耗的所有内存。

对于HTML5本地存储,GWT页面上写着

"LocalStorage:每个浏览器每个应用程序5MB。根据HTML5规范,用户可以在需要时增加此限制;但是,只有少数浏览器支持此限制。“

"SessionStorage:仅受系统内存的限制“

票数 1
EN

Stack Overflow用户

发布于 2012-07-31 00:18:44

由于您使用的是gwt-dispath,因此这里的一个简单解决方案是将gwt-dispath响应对象作为Map中的键对请求对象进行缓存。它很容易实现,而且类型不可知。您需要重写Request - equals()方法来查看请求是否已经在缓存中。如果是,则从缓存返回响应,否则调用服务器。

如果您所需要的只是会话缓存中的性能,那么IMO - LocalStorage在这里不是必需的。本地存储只是离线应用程序的必备项。

你可以看看这个- http://turbomanage.wordpress.com/2010/07/12/caching-batching-dispatcher-for-gwt-dispatch/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11714694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档