SPA(html5单页应用程序)同步本地和远程数据有最佳实践/模式吗?

12

我正在使用jqueryMobile + knockout + breeze + WebAPI编写一个简单的“待办事项-你好世界”应用程序,以学习移动环境下(不可靠的互联网连接)的单页应用程序(SPA)。

为了实现离线使用,WebApp将利用:

  • 应用程序缓存
  • 本地存储

该应用程序应尽可能使用远程数据库来加载和保存数据,但是在离线时应能够无缝切换到本地存储,并在重新联机时同步本地/远程更改。

现在回到问题:

应用程序将使用Breeze的EntityManager来管理数据(本地缓存和远程同步)

  • "remoteDb"

为了减轻不一致性/并发问题,我将使用2个本地存储键:

  • “localDb”用于远程数据库的本地副本(待办事项列表)
  • “localPendingChanges”用于未能提交到远程数据库的更改

因此,大致流程将是(伪代码):

LoadData
  if(online)
    load remoteDb
    save localDb                   // save a local copy of the fresh loaded remotDb
    if(localPendingChanges)
      load localPendingChanges     // we are merging in the Breeze entityManager remote data with localPendingChanges
      Savedata                     // we are online and we have pending changes, so we should sync everything back to the remoteDb as soon as possible
  if(offline)
    load localDb
    if(localPendingChanges)
      load localPendingChanges     // we are merging in the Breeze entityManager local data with localPendingChanges

SaveData
  if(online)
    save remoteDb
    clear localPendingChanges      // until we are online there is no need to keep localPendingChanges
    LoadData                       // we are loading data from remoteDb to update our localDb to the latest version
  if(offline)
    save localPendingChanges       // we are saving only the changes to localstorage

你对这种方法有什么看法?它混乱吗?还是可以接受的?在多用户场景中存在并发问题怎么办?


我正在寻找一个好的方法。虽然我感觉还有更好的方法,但这个方法非常不错。+1 - rpax
2个回答

4
这似乎是合理的,不太确定为什么您需要两个localStorage键。每个实体放置在localStorage中的entityState(未修改,已修改,已添加,已删除)都被维护,所以您可以始终从任何本地副本“提取”(请参见EntityManager.getEntities方法)只有挂起的更改。因此,为什么不在关闭应用程序之前将整个entityManager状态保存到localStorage中呢?
至于并发问题,您应该在每个entityType上设置并发属性。只要存在这个属性,并且如果您通过Entity Framework进行保存,breeze将检测在保存期间任何乐观并发冲突并抛出异常。显然,在此类异常之后,您必须确定应用程序的正确行为。
我相信您已经看到了QueryOptions.MergeStrategy(保留更改,覆盖更改),它可以在任何查询后很有帮助,以保留或覆盖本地计算机上的数据。

我可以理解为何需要单独的键来处理更改。这是一种合理的方式,可以隔离沙盒编辑会话,特别是如果您有几个未保存的沙盒编辑,并且希望它们分别在不同的事务中处理。如果您要在本地“按部就班”地存储待处理的更改以保护用户免受意外或墓碑式失误造成的工作丢失,那么这对我也很有意义。这些更改集可能会很小且短暂;您需要将它们与较大、长期未更改的数据隔离开来。正如您所看到的,这取决于对应用程序需求的清晰理解。 - Ward
1
谢谢Jay,我正在使用EF,所以我一定会遵循你关于并发属性的建议(需要稍微了解一下,直到现在我从未使用过EF :-)) - frenchfaso
我会继续将两个键留在本地存储中,因为尽管这不是必需的(正如你所指出的那样),但我喜欢将它们分开以提高可读性。 - frenchfaso

3
我认为你在将本地更改与与服务器同步的更改分开保存方面是正确的。我已经解决了这个问题几个月,并且想出了一个看起来非常像版本控制系统的东西,其中所有数据都在一个键中,并且每个数据都有单独的版本。您可以将更改从服务器下载到本地数据库中,并且它会通过冲突解决回调处理双方是否都进行了更改。
目前我对Knockout不太了解,但库本身不依赖于任何其他项目,并且在Node.JS、Dojo和jQuery中通过测试用例。它具有超紧凑的API(.get,.set,.feed(用于加载从服务器下载的数据)和.getFirst(用于访问需要上传的内容))。
URL为https://github.com/forbesmyester/SyncIt,它还有相当全面的演示和文档。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接