前言:
在vue项目中,由于功能比较多,需要各种条件控制某个功能、某个标签、表格中的某一行是否显示等,需要使用大量的v-if来判断条件。
例如:
<div v-if="isShow(a, b)">this is a tag</div> <input v-model="c"></input> <script> new Vue({ data () { return { a: 1, b: 2, c: '' } } methods: { isShow(a, b) { console.log('执行ing') return +a + +b === 3 ? true : false } } }) </script>
例如上述代码:
我们在输入框中数据数据,每次数据的变化,isShow方法都会执行一遍,如果项目中含有大量这样的代码,那js的执行就很耗费资源,所以我们需要做一个优化,那就是较少这种类似的计算,并且不影响代码的执行,当然存在函数中的条件变化的之后,才会重新执行,这样就大大减少了代码的执行。
废话不多说开始:
思路:使用闭包的方式,将数据结果进行缓存,如果参数数据发生了变化才会执行,否则直接返回数据的结果,那样就减少了很多逻辑的执行。
但是前提条件是:
类似isShow这个方法,要是纯函数(方法的返回值,只和传入的参数有关)。ps:如果isShow的方法是下面这种是不行的,虽然传入的参数是一样的,但是返回结果可能会受到c值得影响
isShow (a, b) { console.log('执行ing') return +this.c + +a + +b === 3 ? true : false }
所以,isShow方法必须是纯函数。
下面我们需要借用闭包得方式,缓存计算得结果,代码如下:
function single () { const cache = {} // 缓存使用得对象 return function (fn, args) { // 三个参数分别为函数名称,参数 let flagName = `${fn.name}${args.length}` if (cache[flagName]) { // 查找是否存在这个标记 var cacheFn = cache[flagName] // 如果存在,就取出这个对象 if (JSON.stringify(cacheFn.args) == JSON.stringify(args)) { // 判断两次传入得参数是否相同,如果不相同就重新计算,如果相同就直接返回缓存得结果,下面说明为什么使用JSON.stringify return cacheFn.result } else { cacheFn.args = args cacheFn.result = cacheFn.fn.apply(null, args) return cacheFn.result } } else { cache[flagName] = { // 增加这个对象 fn, args, result: fn.apply(null, args) // 执行这个方法 } return cache[flagName].result // 执行返回这个结果 } } }
借助上述得方法,我们对开始得代码进行改造:
<div v-if="single(isShow, [a, b]))">this is a tag</div> <input v-model="c"></input> <script> new Vue({ data () { return { a: 1, b: 2, c: '' } } methods: { isShow(a, b) { console.log('执行ing') return +a + +b === 3 ? true : false } } }) </script>
经过这样得改造,每次输入框中得值发生变化,会执行single方法,在single中,缓存了isShow方法执行得结果,只要a,b两个值发生变化就不会重新执行isShow方法,这样就做到了节省了很多代码得执行
ps:为什么使用JSON.stringify(args)?
例如:
function func (a, b) {} 要判断参数的内容和上次是否一样,使用toString方法可以判断和上次缓存的是否一样 但是如果传入的参数是引用复杂类型('a', {b: 1, c: {d: 2}}),使用JSON.stringify将参数格式化,哪怕是引用类型的一个值或者属性发生变化,都可以对比出不同,至于复杂类型中存在函数、正则,由参数的对象返回结果,不考虑,因为项目中没用到。也没遇到过这么变态的。