Javascript Mobx如何缓存计算值?
我正在使用Mobx构建一个webgl游戏引擎。我没有用它来回应。我正在使用它来增强实体组件系统。我有实体类,比如Javascript Mobx如何缓存计算值?,javascript,mobx,Javascript,Mobx,我正在使用Mobx构建一个webgl游戏引擎。我没有用它来回应。我正在使用它来增强实体组件系统。我有实体类,比如 import {observable, observe, computed, autorun} from 'mobx'; class Entity { @observable position = [0,0,0] @observable rotation = [0,0,0] @computed get modelMat(){ return position *
import {observable, observe, computed, autorun} from 'mobx';
class Entity {
@observable position = [0,0,0]
@observable rotation = [0,0,0]
@computed get modelMat(){
return position * rotation;
}
}
我使用这个实体,比如:
var ent = new Entity();
entity.position = [0,10,0];
if(entity.modelMat == 6){
// do something
}
我的理解是,像这样直接阅读modelMat
不是最佳做法。它会导致重新计算计算的值。它不是缓存的。这在我的游戏引擎中是有害的,因为我可能以60fps这样的高速访问这些计算值
这对我来说似乎不直观,因为您使用get
helper定义了computed,然后不应该将其用作getter?调试computedRequiresReaction
设置可用于防止这种直接计算读取模式
configure({
computedRequiresReaction: true
});
那么,我的问题是如何缓存或记忆这些频繁访问的计算值?为了避免这种情况,我开始使用一种使用自动运行的模式,在计算结果发生变化时更新局部变量。它看起来像:
class Entity {
@observable position = [0,0,0]
@observable rotation = [0,0,0]
modelMat = []
constructor(){
autorun(() => {
this.modelMat = this.computedModelMat()
})
}
@computed get computedModelMat(){
return position * rotation;
}
}
这为类启用了一个接口,因此仍然可以快速访问
ent.modelMat
,但不会每次重新计算它。有没有更好的建议模式?对于每一个计算对象都有一个自动运行似乎是多余的。我的一些类最终拥有许多自动运行处理程序来缓存这些值。是的,您实际上使用的是推荐的方法:
只要一个计算出的值没有被反应所使用,它就不会被记忆,因此它就像一个普通的求值函数一样。如果在自动运行中使用[getter],此行为将发生变化,并且不会看到不必要的计算
MobX以这种方式工作的原因是,只要某个反应
没有使用计算的
值,就可以忽略它。MobX不会全部重新计算,并且计算不会使任何其他计算保持活动状态
但是要小心。问题中的代码没有泄漏,但我不确定您的所有代码:
const VAT=可观察(1.2)
类命令行{
@可观测价格=10
@可观察金额=1
构造函数(){
//此自动运行将与当前orderline实例一起使用
this.handler=自动运行(()=>{
doSomethingWith(this.price*this.amount)
})
//此自动运行不会与当前orderline实例一起被GC删除
//由于VAT保留了通知此自动运行的引用,
//这反过来又保持了“这个”的范围
this.handler=自动运行(()=>{
doSomethingWith(this.price*this.amount*VAT.get())
})
//因此,为了避免细微的内存问题,请始终调用。。
this.handler()
//当反应不再需要时!
}
}
基本上,现在发生的事情是,您正在走出mobx世界,而mobx并不关心它之外的事情。在mobx
系统中,没有任何东西观察计算值,因此没有理由将其缓存(在内存中)
解决这个问题没有好办法
我能为您提供的最好的东西是,当您尝试以您想要/需要的方式编写代码时,有一点更好的开发人员体验
在下面的示例中,请注意cacheComputed()
函数。它将要缓存的实例和属性作为字符串,并简单地围绕它包装autorun
。我们在类的构造函数中使用它。另外,如果您正在处理实例本身,请确保dispose
的autorun
。为此,我通常在实例上有一个dispose()
方法来处理其中的所有反应
处理完后,您应该停止所有反应。
从“mobx”导入{computed,autorun,observable,decoration};
函数cacheComputed(实例、属性){
返回自动运行(反应=>{
返回实例[prop];
//待办事项-如果“道具”不存在,可能会抛出
});
}
甲级{
构造函数(){
this.firstName=“Bob”;
this.lastName=“Marley”;
this.disposeFullName=cacheComputed(这是“全名”);
}
获取全名(){
控制台日志(“计算”);
返回`${this.firstName}${this.lastName}`;
}
处置{
这个.disposeFileName();
}
}
装饰{
名字:可见,
姓氏:可观察,
全名:计算
});
常数a=新的a();
console.log(a.fullName)//缓存
console.log(a.fullName)//缓存
console.log(a.fullName)//缓存
//---强制重新计算
console.log(“----重新计算计算”);
a、 lastName=“Dylan”;
console.log(a.fullName)//重新计算
console.log(a.fullName)//缓存
a、 dispose();//在此之后,将始终重新计算全名
查看请注意,computed支持keepAlive
选项,该选项将强制mobx缓存该值,即使在没有观察者的情况下也是如此。实际上,它比使用自动运行来观察更有效,因为有一些内部优化应用于该标志
不过,内存泄漏的风险很小:如果计算机引用的任何内容仍然存在,那么计算机将不会被清除。然而,如果您只引用类本地内容,则应该保存。谢谢,我曾考虑编写另一个decorator来完成cacheComputed
函数所做的工作。我将接受并奖励这个答案,尽管听起来像下面mweststrate的答案,但听起来像keepAlive
值将满足然而,问题仍然没有完全记录或清楚解释。这种模式有一种令人失望的界面。