reselect 与 vue.computed 属性的区别

1,018 阅读2分钟

目的

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劫持实现缓存,的确比判断结果要方便许多