Javascript 如何处理不一致的mobx状态树快照?

Javascript 如何处理不一致的mobx状态树快照?,javascript,mobx,mobx-state-tree,Javascript,Mobx,Mobx State Tree,我正在编写一个电子应用程序,我将所有应用程序数据保存在一个MST树中。 现在我注意到,有时您会遇到数据不一致的情况(缺少引用对象等)。 虽然任何类型的数据库都可能发生这种情况,但我发现MST存在一个特殊的问题: 由于我们有一个在应用程序启动时反序列化的树,然后用作单个快照,因此单个不一致将导致整个应用程序失败。我的应用程序将无法获得任何数据 有什么关于如何处理的提示吗 更多信息 目前,每当树发生更改时(onSnapshot),我都会创建一个快照,并将其保存在localStorage中。所以一个错

我正在编写一个电子应用程序,我将所有应用程序数据保存在一个MST树中。 现在我注意到,有时您会遇到数据不一致的情况(缺少引用对象等)。 虽然任何类型的数据库都可能发生这种情况,但我发现MST存在一个特殊的问题:

由于我们有一个在应用程序启动时反序列化的树,然后用作单个快照,因此单个不一致将导致整个应用程序失败。我的应用程序将无法获得任何数据

有什么关于如何处理的提示吗

更多信息


目前,每当树发生更改时(onSnapshot),我都会创建一个快照,并将其保存在localStorage中。所以一个错误用例是:创建mst对象->在树的其他部分创建引用->删除mst对象->触发onSnapshot->保存损坏的树。重新加载应用程序不会有帮助,因为树一直处于损坏状态

反序列化的数据来自哪里?我对electron不太熟悉,但我想你可以在应用程序会话之间本地存储它(通过拍摄mst树)

  • 我的第一个预感是看看当你把它序列化时会发生什么?也许在保存快照之前验证快照是个好主意(我想是在appclose上?)

  • 不一致性是否“一致”?我的意思是-是树的同一部分引起的吗?也许拆分树-序列化->反序列化不同部分的多个快照,而不是一个大东西

  • 虽然我使用mst,但我不使用快照,至少在整个树级别上不使用,检查创建快照时树是否冻结。。也许,我认为不太可能,在编写快照时,仍然在树上进行更改


  • 为了避免传入的数据不一致,我在模型中添加了默认值。 比如说

    const collectionModel = types.model({
      type: types.optional(types.literal('collections'), 'collections'),
      preview: types.optional(
        types.model({
          products: types.array(SelectableProduct)
        }),
        {}
      ),
      data: types.optional(types.model({
        items: 24,
        perRow: 4,
        global: types.optional(EvergreenQuery, {}),
        curated: types.array(EvergreenItemSettings)
      }), {})
    })
    
    这将允许我从空对象创建
    collectionModel
    的实例

    collection1 = collectionModel.create({})
    
    使用参考资料时,请确保使用
    safeReference
    从文件中

     * `types.safeReference` - A safe reference is like a standard reference, except that it accepts the undefined value by default
     * and automatically sets itself to undefined (when the parent is a model) / removes itself from arrays and maps
     * when the reference it is pointing to gets detached/destroyed.
     *
     * Strictly speaking it is a `types.maybe(types.reference(X))` with a customized `onInvalidate` option.
    
    因此,如果要删除存储中其他地方引用的节点,则该引用将设置为“未定义”。 根据我的经验,断开的引用尤其难以调试

    我喜欢mobx状态树迫使我有一个定义的结构。这让我在写逻辑之前先考虑结构,然后再简化逻辑的编写

    不切实际的解决办法 您可以在保存快照之前对新模型进行实例化。如果成功,则保存快照,如果不保存,则跳过快照

    const MyModel = types.model({})
    
    onSnapshot(myModelInstance, s => {
      try {
        const testModel = MyModel.create(s)
        if (localStorage) {
          // here you can save the snapshot because you know for sure it won't break
    
          localStorage.setItem('snap', JSON.stringify(s))
        }
      } catch(e) {
        // log or something
    
        // OR
        console.log(
          'snapshot failed because of',
           difference(s, JSON.parse(localStorage.getItem('snap'))
        )
      }
    })
    
    
    
    // this methos does a deep difference between two objects
    export const difference = <T>(orObject: object, orBase: object): T => {
      function changes(object: any, base: any): any {
        return _.transform(object, function(
          result: any,
          value: any,
          key: any
        ): any {
          if (!_.isEqual(value, base[key])) {
            result[key] =
              _.isObject(value) && _.isObject(base[key])
                ? changes(value, base[key])
                : value;
          }
        });
      }
    
      return changes(orObject, orBase);
    };
    
    constmymodel=types.model({})
    onSnapshot(myModelInstance,s=>{
    试一试{
    const testModel=MyModel.create(s)
    if(本地存储){
    //在这里,您可以保存快照,因为您确信它不会中断
    localStorage.setItem('snap',JSON.stringify))
    }
    }捕获(e){
    //日志什么的
    //或
    console.log(
    '快照失败,因为',
    差异(s,JSON.parse(localStorage.getItem('snap'))
    )
    }
    })
    //这种方法在两个物体之间有很大的区别
    导出常量差=(orObject:object,orBase:object):T=>{
    函数更改(对象:任意,基:任意):任意{
    返回转换(对象、函数)(
    结果:任何,
    价值:任何,
    钥匙:有吗
    ):任何{
    if(!\ isEqual(值,基[键]){
    结果[关键]=
    _.isObject(值)和&.isObject(基[键])
    ?更改(值、基[键])
    :价值;
    }
    });
    }
    返回更改(orObject、orBase);
    };
    

    diff方法非常有用,因为它可以更容易地找出崩溃的原因。这样,localStorage将只有有效的快照,任何无效的快照都将记录问题的原因。

    这听起来确实是一个严重的问题。如果您可以创建可复制的代码沙盒,您可能应该打开一个github上的罚单。这是怎么回事,你是否发现了导致不一致的原因?或者你如何处理?任何后续行动可能对我们这里也有帮助。我还没有实现它,但我计划每10秒验证一次我的存储,只有在验证成功时才保存它。