加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

浅谈Vue 初始化性能优化

发布时间:2020-12-17 02:48:57 所属栏目:百科 来源:网络整理
导读:前言 一般来说,你不需要太关心vue的运行时性能,它在运行时非常快,但付出的代价是初始化时相对较慢。在最近开发的一个Hybrid APP里,Android Webview初始化一个较重的vue页面竟然用了1200ms ~ 1400ms,这让我开始重视vue的初始化性能,并最终优化到200 ~ 3

前言

一般来说,你不需要太关心vue的运行时性能,它在运行时非常快,但付出的代价是初始化时相对较慢。在最近开发的一个Hybrid APP里,Android Webview初始化一个较重的vue页面竟然用了1200ms ~ 1400ms,这让我开始重视vue的初始化性能,并最终优化到200 ~ 300ms,这篇文章分享我的优化思路。

性能瓶颈在哪里?

先看一下常见的vue写法:在html里放一个app组件,app组件里又引用了其他的子组件,形成一棵以app为根节点的组件树。

而正是这种做法引发了性能问题,要初始化一个父组件,必然需要先初始化它的子组件,而子组件又有它自己的子组件。那么要初始化根标签,就需要从底层开始冒泡,将页面所有组件都初始化完。所以我们的页面会在所有组件都初始化完才开始显示。

这个结果显然不是我们要的,更好的结果是页面可以从上到下按顺序流式渲染,这样可能总体时间增长了,但首屏时间缩减,在用户看来,页面打开速度就更快了。

要实现这种渲染模式,我总结了下有3种方式实现。第3种方式是我认为最合适的,也是我在项目中实际使用的优化方法。

第一种:不使用根组件

这种方式非常简单,例如:

抛弃了根组件,从而使A、B、C每一个组件初始化完都立刻展示。但根组件在SPA里是非常必要的,所以这种方式只适用小型页面。

第二种:异步组件

异步组件在官方文档已有说明,使用非常简单:

{ resolve({ /*component-config*/ }) },0); } } })

这里组件是一个异步组件,会等到手动调用resolve函数时才开始初始化,而父组件也不必等待先初始化完。

我们利用setTimeout(fn,0)将的初始化放在队列最后,结果就是页面会在初始化完后立刻显示,然后再显示。如果你的页面有几十个组件,那么把非首屏的组件全设成异步组件,页面显示速度会有明显的提升。

你可以封装一个简单的函数来简化这个过程:

{ window.setTimeout(() => resolve(component),time) }; }

new Vue({
components: {
B: deferLoad( /component-config/ ),// 100ms后渲染
C: deferLoad( /component-config/,100 )
}
})

看起来很美好,但这种方式也有问题,考虑下这样的结构:

还是按照上面的异步组件做法,这时候就需要考虑把哪些组件设成异步的了。如果把A、B、C都设成异步的,那结果就是3个会首先渲染出来,页面渲染的过程在用户看来非常奇怪,并不是预期中的从上到下顺序渲染。</p> <p><h3>第三种:v-if 和 terminal指令</h3> </p> <p>这是我推荐的一种做法,简单有效。还是那个结构,我们给要延迟渲染的组件加上v-if:</p> <div class="jb51code"> <pre class="brush:xhtml;"> <B v-if="showB"></B> <C v-if="showC"></C> </app> </pre> </div> <div class="jb51code"> <pre class="brush:js;"> new Vue({ data: { showB: false,showC: false },created () { // 显示B setTimeout(() => { this.showB = true; },0); // 显示C setTimeout(() => { this.showC = true; },0); } }); </pre> </div> <p>这个示例写起来略显啰嗦,但它已经实现了我们想要的顺序渲染的效果。页面会在A组件初始化完后显示,然后再按顺序渲染其余的组件,整个页面渲染方式看起来是流式的。</p> <p>有些人可能会担心v-if存在一个编译/卸载过程,会有性能影响。但这里并不需要担心,因为v-if是惰性的,只有当第一次值为true时才会开始初始化。</p> <p>这种写法看起来很麻烦,如果我们能实现一个类似v-if的组件,然后直接指定多少秒后渲染,那就更好了,例如:</p> <div class="jb51code"> <pre class="brush:xhtml;"> <B v-lazy="0"></B> <C v-lazy="100"></C> </app></pre> </div> <p>一个简单的指令即可,不需要js端任何配合,并且可以用在普通dom上面,Nice!</p> <p>在vue里,类似v-if和v-for这种是terminal指令,会在指令内部编译组件。如果你想要自己实现一个terminal指令,需要加上terminal: true,例如:</p> <div class="jb51code"> <pre class="brush:js;"> Vue.directive('lazy',{ terminal: true,bind () {},update () {},unbind () {} });</pre> </div> <p>这是vue在1.0.19+新增的功能,由于比较冷门,文档也没有特别详细的叙述,最好的方式是参照着v-if和v-for的源码来写。</p> <p>我已经为此封装了一个terminal指令,你可以直接使用:https://github.com/Coffcer/vu...</p> <p><h3>其他的优化点</h3> </p> <p>除了组件上的优化,我们还可以对vue的依赖改造入手。初始化时,vue会对data做getter、setter改造,在现代浏览器里,这个过程实际上挺快的,但仍然有优化空间。</p> <p><code>Object.freeze()</code>是ES5新增的API,用来冻结一个对象,禁止对象被修改。vue 1.0.18+以后,不会对已冻结的data做getter、setter转换。</p> <p>如果你确保某个data不需要跟踪依赖,可以使用Object.freeze将其冻结。但请注意,被冻结的是对象的值,你仍然可以将引用整个替换调。看下面例子:</p> <div class="jb51code"> <pre class="brush:xhtml;"> <p v-for="item in list">{{ item.value }}</p></pre> </div> <div class="jb51code"> <pre class="brush:js;"> new Vue({ data: { // vue不会对list里的object做getter、setter绑定 list: Object.freeze([ { value: 1 },{ value: 2 } ]) },created () { // 界面不会有响应 this.list[0].value = 100; <pre><code>// 下面两种做法,界面都会响应 this.list = [ { value: 100 },{ value: 200 } ]; this.list = Object.freeze([ { value: 100 },{ value: 200 } ]);</code></pre> <p>}<br /> })</p> </pre> </div> <p><h3>后记</h3> </p> <p>vue 1.0+ 的组件其实不算轻量,初始化一个组件包括依赖收集、转换等过程,但其实有些是可以放在编译时提前完成的。vue 2.0+ 已经在这方面做了不少的改进:分离了编译时和运行时、提供函数组件等,可以预见,vue 2.0的性能将有很大的提升。</p> <p>v-lazy-component: https://github.com/Coffcer/vu... </p> <p>以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。</p> <p style="text-align:right;">(编辑:李大同)</p> <p style="text-align:right;">【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!</p> </td> </tr> </table> </div> <div class="dede_pagess"><ul class="pagelist"></ul></div> <div class="ad-690"><script src='https://ess.0577qiche.com/d/js/acmsd/ad76.js' language='javascript'></script></div> <div class="g-box10"> <div class="t-2">相关内容</div> <ul class="b-box12"></ul> <ul class="b-box13"><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/465171.html" target="_blank">XML解析工具类</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/312964.html" target="_blank">在C#4.0中使用动态的RuntimeBinderException</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/333953.html" target="_blank">(2)stm32开发之使用Keil MDK以及标准外设库创建STM32工程</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/341418.html" target="_blank">如何制作CRAMFS + YAFFS2文件系统</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1214/184121.html" target="_blank">如何用 Parse 和 Swift 搭建一个像 Instagram 那样的应用?</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1217/562002.html" target="_blank">vb.net UI multi Split</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1212/57435.html" target="_blank">r语言导入oracle数据中文是问号</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/421840.html" target="_blank">Ajax实现用户名验证</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/457737.html" target="_blank">xsl与xml的综合应用-换色换值显示</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/450113.html" target="_blank">tsql – 如何在CAST / CONVERT之前检查VARCHAR(n)格式良好的</a></li><div class="cl"></div></ul> </div> </div> </div> <div class="right-1 fr"> <div class="g-box8"> <div class="t-2">推荐文章</div> <ul></ul> </div> <div class="g-box11"> <div class="t-2">站长推荐</div> <ul class="b-box7"><li><a href="https://www.lidatong.com.cn/html/baike/2020/1217/544262.html" target="_blank">Sublime Text新建.vue模板并高亮(图文教程)</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/403908.html" target="_blank">在String.xml中使用特殊符号</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1214/197869.html" target="_blank">swift – 比较NSDate</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/399635.html" target="_blank">DWR + ssh2 项目实例</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/324673.html" target="_blank">amChart for Flex 破解</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/498961.html" target="_blank">json2.js 简析(个人学习)</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/515209.html" target="_blank">ruby轨道 – 在Heroku使用虾</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1215/391337.html" target="_blank">c# – 扩展ASP.NET资源提供程序</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1216/498833.html" target="_blank">脱离jsonp,如何跨域读取、提交数据</a></li><li><a href="https://www.lidatong.com.cn/html/baike/2020/1212/55020.html" target="_blank">Oracle 窗口函数over()与窗口子语句</a></li></ul> </div> <script type="text/javascript">jQuery(".g-box8").slide({ titCell:"li",triggerTime:0 }); </script> <div class="ad-250"><script src='https://ess.0577qiche.com/d/js/acmsd/ad103.js' language='javascript'></script></div> <div class="g-box3 u-3"> <div class="t-1">热点阅读</div> <ul class="b-box2"></ul> </div> <div class="ad-250"><script src='https://ess.0577qiche.com/d/js/acmsd/ad77.js' language='javascript'></script></div> </div> <div class="cl"></div> </div> <div class="ad-960"><script src='https://ess.0577qiche.com/d/js/acmsd/ad78.js' language='javascript'></script></div> <div class="footer"> <p>【免责声明】本站内容转载自互联网,其发布内容言论不代表本站观点,如果其链接、内容的侵犯您的权益,烦请提交相关链接至邮箱bqsm@foxmail.com我们将及时予以处理。</p> <p>建议您使用1920×1080分辨率、谷歌浏览器Google Chrome、Microsoft Edge以获得本站的最佳浏览效果</p> <p>Copygight © 2008-2022 https://www.lidatong.com.cn/ All Rights Reserved. 李大同</p> <p><script type="text/javascript" src="//js.users.51.la/21280179.js"></script></p> </div> </body> </html>