Javascript Mobx如何缓存计算值?

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 *

我正在使用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 * 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
值将满足然而,问题仍然没有完全记录或清楚解释。这种模式有一种令人失望的界面。