目的
reselect 和 computed 都是为了缓存计算的结果,再数据源没有修改的情况下,不执行计算的过程,直接拿到计算结果。
用代码解释使用计算属性
class computed {
constructor() {
this.getValue()
}
start = 1
res = null
getValue() {
let res = this.start
for (let i = 1; i < 100; i++) {
res = res * i
}
this.res=res
return this.res
}
}
var a =computed()
//以后可以直接从value取值,只需要计算一次
console.log(a.res)
常规函数返回
function getValue(start){
let res=start
for(let i =1;i<100;i++){
res=res*i
}
return res
}
//每次取值,都要跑一遍函数
console.log(getValue())
//当然你也可以 const value =getValue(),囧。
毫无疑问,在使用计算属性,处理大批量数据的时候,明显优于第二种直接函数求值。
但是以上计算属性有一个明显的问题,而这个问题,正涉及到 reselect 和 computed 不同的解决方案。
问题是:如何判断值是取缓存,还是重新求值。
比如上文的 形参 start 发生了变化,计算属性中的value如何变化?
总的来说
computed 是拦截 set (在第一次求值的过程中,触发了 get 依赖收集) reselect 是判断传入的变量(比如判断第一次的 start 与新传入的 start,是否相同)
具体实现
computed
在对 start 进行赋值的时候,直接触发计算过程
class computed {
constructor() {
this.getValue()
}
setStart(value){
this.start=value
return this.getValue()
}
start = 1
res = null
getValue() {
let res = this.start
for (let i = 1; i < 100; i++) {
res = res * i
}
this.res=res
return this.res
}
}
var a =computed()
console.log(a.res)
console.log(a.setStart(5))
console.log(a.res)
reselect
const reselectCreate = createSelector(...arg , fn) //整个业务中,只执行一次
const reselect =reselectCreate(state) //在不同组件中,进行多次初始化
// 这里的 fn 等于 computed 中的 getValue
// 而这里的 arg 等于 computed 中的 start
问题是 reselect 是如何进行缓存判断的?
每次传入state的时候,会先执行 arg 中的函数(主要是取值,不涉及运算)并缓存 arg 的结果,
如果arg的结果一致,则跳过fn的求值过程(输入源不变,没必要再跑一次),返回旧值。
如果不一致,则触发计算,返回新的值
所以这里一般是 === 进行缓存命中,但这个其实有个问题,就是引用类型。
如果传入的都是同一个对象,由于引用地址都是一致的,
如果对象内的属性修改了,因此并不会触发重新求值的过程,对于新人而言,很容易踩坑。
所以,使用 reselect 库的时候,一般会引用另一个第三方库 immutable.js 。
注: reselect 默认是使用 === 判断相等的,如果是用 immutable , 需要修改判断函数。
所以总的来说...vue,在计算缓存这方面来说,有巨大的框架思想特点。
不得不说set劫持实现缓存,的确比判断结果要方便许多