使用EmberData在本地存储器中caching远程数据
我有一个关于使用Ember加载和caching远程对象的问题。 我正在开发一个通过REST API使用服务器端存储的Ember应用程序。 一些获取的数据很less发生变化,因此每次应用程序加载时从服务器获取数据是不必要的。 但是,这也是一个需要离线工作的应用程序的问题,并仍然将其数据保存到服务器。
Ember Data有一个内置的存储适配器,用于通过REST API持久保存模型,并且还有一个适用于本地存储的适配器 (正如Ken所指出的那样)。 问题(如果是问题)是一个模型只有一个存储适配器,似乎没有任何caching提取的模型的概念,而不是将它们保存在内存中。
我在这个Ember的愿望清单以及Tom Dale对这个演讲的评论中发现了类似的要求,但我还没有发现任何迹象表明这是Ember中的一个现有function。
我有两个问题(第一个是重要问题):
- 什么是今天最好的方式 – 在本地存储中实现caching模型并根据需要与远程数据同步?
- 这是一个计划包含在Ember中的function,或者至less是维护者认为最终应该添加的东西?
当谈到1),我可以想到几个策略:
a)扩展现有适配器并添加自定义远程同步机制:
App.Store.registerAdapter('App.Post', DS.LSAdapter.extend({ // do stuff when stuff happens }));
b)保持单独的模型类 – 一组用于远程对象,一组用于本地对象 – 并根据需要在它们之间进行同步。 有了标准的Todo案例:
RemoteTodo –*sync*– Todo | UI
我有点希望这是一个真正的低调问题,并有一个良好的既定模式。
更新:find这个类似的问题 。 它有一个很好的答案,但这是一种理论。 我想我需要的是一些实际的提示或示例实现的指针。
只是为了“碰撞”这个线程,因为它是当我研究解决scheme的余烬api的烬本地caching时,最重要的结果之一:
Dan Gebhardt似乎在Orbit.js上做了一个很好的工作,并且把它整合到了Ember中: https : //github.com/orbitjs/ember-orbit
Orbit是一个独立的库,用于协调对数据源的访问并保持内容的同步 。
Orbit为在客户端应用程序中构build高级function(如脱机操作,本地caching的维护和同步,撤销/重做堆栈和临时编辑上下文)提供了基础。
Orbit.js特点:
在应用程序中支持任意数量的不同数据源,并通过通用接口提供对它们的访问。
允许不同来源的请求的履行,包括指定优先和备用计划的能力。
允许logging同时存在于不同来源的不同州。
跨源协调转换。 在可能的情况下自动处理合并,但允许完全自定义控制。
允许阻塞和非阻塞转换。
允许同步和asynchronous请求。
通过跟踪操作反向支持事务和撤销/重做。
使用普通的JavaScript对象。
不要错过他的伟大的演讲和关于轨道的幻灯片:
Orbit.js简介
( 更新 :我从Orbit页面添加了一些更多的描述性信息,因为我的post因为“只是”引用了外部资源而没有包含实际的解决scheme而被低估了,但是Orbit在我看来似乎是解决scheme,而唯一的办法就是“包括“这里是通过链接。)
有一个本地存储适配器的实现,你可能会觉得有用。 看看https://github.com/rpflorence/ember-localstorage-adapter
这是一个办法。 一个适配器的mixin,使用一个localStoreRecord
方法可以cachinglogging,最后是一个初始化器来预先加载商店。
本地存储只是一个键值对象的值存储,所以我们可以将所有的应用程序数据存储在一个键中。
注意:这是使用es6模块
// app/mixins/local-storage.js import Ember from 'ember'; export default Ember.Mixin.create({ appName: 'myApp', // how many records per model to store locally, can be improved. // needed to prevent going over localStorage's 5mb limit localStorageLimit: 5, localStoreRecord: function(record) { var data = JSON.parse(localStorage.getItem(this.appName)); data = data || {}; data[this.modelName] = data[this.modelName] || []; var isNew = data[this.modelName].every(function(rec) { rec.id !== record.id; }); if (isNew) { data[this.modelName].push(record); if (data[this.modelName].length > this.localStorageLimit) { data[this.modelName].shift(); } localStorage.setItem(this.appName, JSON.stringify(data)); } } });