Vue中避免滥用this去读取data中数据的方法是什么
这篇文章主要讲解了"Vue中避免滥用this去读取data中数据的方法是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Vue中避免滥用this去读取data中数据的方法是什么"吧!
一、用this读取data中数据的过程
在Vue源码中会把data中数据添加getter函数和setter函数,将其转成响应式的。getter函数代码如下所示:
function reactiveGetter() { var value = getter ? getter.call(obj) : val; if (Dep.target) { dep.depend(); if (childOb) { childOb.dep.depend(); if (Array.isArray(value)) { dependArray(value); } } } return value }
用this读取data中数据时,会触发getter函数,在其中通过 var value = getter ? getter.call(obj) : val; 获取到值后执行 return value,实现读取数据的目的。
但是在其间还有一段代码,在这段代码中会经过一系列复杂的逻辑运算来收集依赖。这里只要知道在Dep.target存在时才会去收集依赖。
这里可以得出一个结论,在Dep.target存在时,使用this去读取data中数据时会去收集依赖。如果滥用this去读取data中数据,会多次重复地收集依赖,从而产生性能问题。
二、Dep.target什么时候存在
Dep.target是由依赖赋值的。依赖又称为Watcher(侦听者)或者订阅者。在Vue中有三种依赖,其中两种是很常见的,就是watch(侦听器)和computed(计算属性)。还有一种隐藏的依赖———渲染Watcher,在模板首次渲染的过程中创建的。
Dep.target是在依赖创建时被赋值,依赖是用构造函数Watcher创建。
lue = this.lazy ? undefined : this.get(); }; Watcher.prototype.get = function get() { pushTarget(this); try { value = this.getter.call(vm, vm); } catch (e) { }function Watcher(vm, expOrFn, cb, options, isRenderWatcher) { //... if (typeof expOrFn === 'function') { this.getter = expOrFn; } else { this.getter = parsePath(expOrFn); } this.va return value }; Dep.target = null; var targetStack = []; function pushTarget(target) { targetStack.push(target); Dep.target = target; }
在构造函数Watcher最后会执行实例方法get,在实例方法get中执行pushTarget(this)中给Dep.target赋值的。
而依赖是在Vue页面或组件初次渲染时创建,所以产生的性能问题应该是首次渲染过慢的问题。
三、在何处滥用this去读取data中数据
在Dep.target存在时去执行这些滥用this去读取data中数据的代码会产生性能问题,故还要搞清楚这些代码是写在哪里才会被执行到,换句话来说,要搞清楚在哪里滥用this去读取data中数据会产生性能问题。
在第二小节中介绍了Dep.target被赋值后会执行value = this.getter.call(vm, vm),其中this.getter是一个函数,那么若在其中有用this去读取data数据,就会去收集依赖,假如滥用的话就会产生性能问题。
this.getter是在创建依赖过程中赋值的,每种依赖的this.getter都是不相同的。下面来一一介绍。
watch(侦听器)依赖的this.getter是parsePath函数,其函数参数就是侦听的对象。
var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]")); function parsePath(path) { if (bailRE.test(path)) { return } var segments = path.split('.'); return function(obj) { for (var i = 0; i < segments.length; i++) { if (!obj) { return } objobj = obj[segments[i]]; } return obj } }
如下所示的代码中的 a 和 a.b.c作为参数传入parsePath函数会返回一个函数赋值给this.getter,执行this.getter.call(vm, vm)会得到this.a和this.a.b.c的值。在这个过程中不会存在滥用this去读取data中数据的场景。
watch:{ a:function(newVal, oldVal){ //做点什么 } } vm.$watch('a.b.c', function (newVal, oldVal) { // 做点什么 })
computed(计算属性)依赖的this.getter有两种,如果计算属性的值是个函数,那么this.getter就是这个函数。如果计算属性的值是个对象,那么this.getter就是这个对象的get属性值,get属性值也是个函数。在这个函数可能会存在滥用this去读取data中数据的场景,举个例子,代码如下所示。
computed:{ d:function(){ let result = 0; for(let key in this.a){ if(this.a[key].num > 20){ result += this.a[key].num + this.b + this.c; }else{ result += this.a[key].num + this.e + this.f; } } return result; } }
在计算属性d中就存在滥用this去读取data数据。其中this.a是个数组,此时Dep.target的值为计算属性d这个依赖,在循环this.a中使用this去获取中a、b、c、e、f的数据,使这些数据进行一系列复杂的逻辑运算来重复地收集计算属性d这个依赖。导致获取计算属性d的值的速度变慢,从而产生性能问题。
渲染Watcher的this.getter是一个函数如下所示:
updateComponent = function() { vm._update(vm._render(), hydrating); };
其中vm._render()会把template模板生成的渲染函数render转成虚拟DOM(VNode):vnode = render.call(vm._renderProxy, vm.$createElement);,举一个例子来说明一下渲染函数render是什么。
例如template模板:
{{a}}{{b}}
通过vue-loader会生成渲染函数render,如下所示:
(function anonymous() { with(this) { return _c('div', { attrs: { "class": "wrap" } }, [_c('p', [_v(_s(a)), _c('span', [_v(_s(b))])])]) } })
其中with语句的作用是为一个或一组语句指定默认对象,例with(this){ a + b } 等同 this.a + this.b,那么在template模板中使用{{ a }}相当使用this去读取data中的a数据。故在template模板生成的渲染函数render中也可能存在滥用this去读取data中数据的场景。举个例子,代码如下所示:
{{ arr[item.index]['name'] }}{{ obj[item.id]['age'] }}
其中用v-for循环list数组过程中,不断用this去读取data中arr、obj的数据,使这些数据进行一系列复杂的逻辑运算来重复收集这个依赖,导致初次渲染的速度变慢,从而产生性能问题。
四、如何避免滥用this去读取data中数据
综上所述在计算属性和template模板中滥用this去读取data中数据会导致多次重复地收集依赖,从而产生性能问题,那要怎么避免这种情况。
计算属性中如何避免
用ES6对象解构赋值来避免,计算属性的值是一个函数,其参数是Vue的实例化this对象,在上述计算属性中滥用this的例子中可以这样优化。
优化前:
computed:{ d:function(){ let result = 0; for(let key in this.a){ if(this.a[key].num > 20){ result += this.a[key].num + this.b + this.c; }else{ result += this.a[key].num + this.e + this.f; } } return result; } }
优化后:
computed: { d({ a, b, c, e, f }) { let result = 0; for (let key in a) { if (a[key].num > 20) { result += a[key].num + b + c; } else { result += a[key].num + e + f; } } return result; } }
以上利用解构赋值提前把data数据中的a、b、c、e、f赋值给对应的变量a、b、c、e、f,然后在计算属性中可以通过这些变量访问data数据的,且不会触发data中对应数据的依赖收集。这样只用this读取了一次data中的数据,只触发了一次依赖收集,避免了多次重复地依赖收集产生的性能问题。
template模板中如何避免
提前处理v-for循环所用的数据,不要在v-for循环中去读取数组、对象类型的数据。在上述template模板中滥用this的例子中可以这样优化。
假设list、arr、obj皆是服务端返回来的数据,且arr和obj没有用到任何模块渲染中,可以这样优化。
优化前:
{{ arr[item.index]['name'] }}{{ obj[item.id]['age'] }}
优化后:
{{item.age}}感谢各位的阅读,以上就是"Vue中避免滥用this去读取data中数据的方法是什么"的内容了,经过本文的学习后,相信大家对Vue中避免滥用this去读取data中数据的方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
数据 函数 属性 问题 性能 代码 模板 对象 方法 例子 就是 过程 是在 循环 复杂 参数 场景 实例 逻辑 学习 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 大同软件开发公司电话 浪潮服务器经销商 国家网络安全黑板报初中 膏广告数据库10秒 深圳市菁致网络技术 甘肃省网络安全宣传周在天水启动 测试服务器测试是否开通 数据库 非结构化数据 广东著名的网络安全公司 欧洲 软件开发 薪水 深圳上市的网络安全公司 戴尔服务器r910 畅捷通软件开发 徐州多功能软件开发行业 数据库取出的时间 对工业网络技术的见解 关于网络安全管理的建议 网络技术在英语中的应用 柚子基因组数据库 编辑服务器怎么卸载 软件开发个人简介模板范文 饥荒一直显示启动服务器有点问题 lol掉线无法连接服务器 用迅雷在服务器文件夹里下载 河北文档软件开发哪家好 出纳通 sql附加数据库 乳山软件开发怎么选 服务器 iis网站配置 赵一鸣是什么软件开发者 长沙APP软件开发最新招聘信息