Javascript 如何处理不一致的mobx状态树快照?
我正在编写一个电子应用程序,我将所有应用程序数据保存在一个MST树中。 现在我注意到,有时您会遇到数据不一致的情况(缺少引用对象等)。 虽然任何类型的数据库都可能发生这种情况,但我发现MST存在一个特殊的问题: 由于我们有一个在应用程序启动时反序列化的树,然后用作单个快照,因此单个不一致将导致整个应用程序失败。我的应用程序将无法获得任何数据 有什么关于如何处理的提示吗 更多信息Javascript 如何处理不一致的mobx状态树快照?,javascript,mobx,mobx-state-tree,Javascript,Mobx,Mobx State Tree,我正在编写一个电子应用程序,我将所有应用程序数据保存在一个MST树中。 现在我注意到,有时您会遇到数据不一致的情况(缺少引用对象等)。 虽然任何类型的数据库都可能发生这种情况,但我发现MST存在一个特殊的问题: 由于我们有一个在应用程序启动时反序列化的树,然后用作单个快照,因此单个不一致将导致整个应用程序失败。我的应用程序将无法获得任何数据 有什么关于如何处理的提示吗 更多信息 目前,每当树发生更改时(onSnapshot),我都会创建一个快照,并将其保存在localStorage中。所以一个错
目前,每当树发生更改时(onSnapshot),我都会创建一个快照,并将其保存在localStorage中。所以一个错误用例是:创建mst对象->在树的其他部分创建引用->删除mst对象->触发onSnapshot->保存损坏的树。重新加载应用程序不会有帮助,因为树一直处于损坏状态 反序列化的数据来自哪里?我对electron不太熟悉,但我想你可以在应用程序会话之间本地存储它(通过拍摄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秒验证一次我的存储,只有在验证成功时才保存它。