Android Webview中Vue初始化的性能优化

简介:

前言

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

性能瓶颈在哪里?

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


  
  
  1. <body> 
  2.     <app></app>  
  3. </body>  

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

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

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

第一种:不使用根组件

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


  
  
  1. <body> 
  2.     <A></A> 
  3.     <B></B> 
  4.     <C></C> 
  5. </body>  

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

第二种:异步组件

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


  
  
  1. <app> 
  2.     <A></A> 
  3.     <B></B> 
  4. </app>  

  
  
  1. new Vue({ 
  2.     components: { 
  3.         A: { /*component-config*/ }, 
  4.         B (resolve) { 
  5.             setTimeout(() => { 
  6.                 resolve({ /*component-config*/ }) 
  7.             }, 0); 
  8.         } 
  9.     } 
  10. })  

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

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

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


  
  
  1. function deferLoad (component, time = 0) { 
  2.     return (resolve) => { 
  3.         window.setTimeout(() => resolve(component), time
  4.     }; 
  5.  
  6. new Vue({ 
  7.     components: { 
  8.         B: deferLoad( /*component-config*/ ), 
  9.         // 100ms后渲染 
  10.         C: deferLoad( /*component-config*/, 100 ) 
  11.     } 
  12. }) 

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


  
  
  1. <app> 
  2.     <title></title> 
  3.     <A></A> 
  4.     <title></title> 
  5.     <B></B> 
  6.     <title></title> 
  7.     <C></C> 
  8. </app>  

还是按照上面的异步组件做法,这时候就需要考虑把哪些组件设成异步的了。如果把A、B、C都设成异步的,那结果就是3个<title>会首先渲染出来,页面渲染的过程在用户看来非常奇怪,并不是预期中的从上到下顺序渲染。

第三种:v-if 和 terminal指令

这是我推荐的一种做法,简单有效。还是那个结构,我们给要延迟渲染的组件加上v-if:


  
  
  1. <app> 
  2.     <A></A> 
  3.     <B v-if="showB"></B> 
  4.     <C v-if="showC"></C> 
  5. </app>  

  
  
  1. new Vue({ 
  2.     data: { 
  3.         showB: false
  4.         showC: false 
  5.     }, 
  6.     created () { 
  7.         // 显示B 
  8.         setTimeout(() => { 
  9.             this.showB = true
  10.         }, 0); 
  11.         // 显示C 
  12.         setTimeout(() => { 
  13.             this.showC = true
  14.         }, 0); 
  15.     } 
  16. });  

这个示例写起来略显啰嗦,但它已经实现了我们想要的顺序渲染的效果。页面会在A组件初始化完后显示,然后再按顺序渲染其余的组件,整个页面渲染方式看起来是流式的。

有些人可能会担心v-if存在一个编译/卸载过程,会有性能影响。但这里并不需要担心,因为v-if是惰性的,只有当第一次值为true时才会开始初始化。

这种写法看起来很麻烦,如果我们能实现一个类似v-if的组件,然后直接指定多少秒后渲染,那就更好了,例如:


  
  
  1. <app> 
  2.     <A></A> 
  3.     <B v-lazy="0"></B> 
  4.     <C v-lazy="100"></C> 
  5. </app>  

一个简单的指令即可,不需要js端任何配合,并且可以用在普通dom上面,Nice!

在vue里,类似v-if和v-for这种是terminal指令,会在指令内部编译组件。如果你想要自己实现一个terminal指令,需要加上terminal: true,例如:


  
  
  1. Vue.directive('lazy', { 
  2.     terminal: true
  3.     bind () {}, 
  4.     update () {}, 
  5.     unbind () {} 
  6. });  

这是vue在1.0.19+新增的功能,由于比较冷门,文档也没有特别详细的叙述,最好的方式是参照着v-if和v-for的源码来写。

我已经为此封装了一个terminal指令,你可以直接使用:

https://github.com/Coffcer/vu...

其他的优化点

除了组件上的优化,我们还可以对vue的依赖改造入手。初始化时,vue会对data做getter、setter改造,在现代浏览器里,这个过程实际上挺快的,但仍然有优化空间。

Object.freeze()是ES5新增的API,用来冻结一个对象,禁止对象被修改。vue 1.0.18+以后,不会对已冻结的data做getter、setter转换。

如果你确保某个data不需要跟踪依赖,可以使用Object.freeze将其冻结。但请注意,被冻结的是对象的值,你仍然可以将引用整个替换调。看下面例子:


  
  
  1. <p v-for="item in list">{{ item.value }}</p>  

  
  
  1. new Vue({ 
  2.     data: { 
  3.         // vue不会对list里的object做getter、setter绑定 
  4.         list: Object.freeze([ 
  5.             { value: 1 }, 
  6.             { value: 2 } 
  7.         ]) 
  8.     }, 
  9.     created () { 
  10.         // 界面不会有响应 
  11.         this.list[0].value = 100; 
  12.  
  13.         // 下面两种做法,界面都会响应 
  14.         this.list = [ 
  15.             { value: 100 }, 
  16.             { value: 200 } 
  17.         ]; 
  18.         this.list = Object.freeze([ 
  19.             { value: 100 }, 
  20.             { value: 200 } 
  21.         ]); 
  22.     } 
  23. })  

后记

vue 1.0+ 的组件其实不算轻量,初始化一个组件包括依赖收集、转换等过程,但其实有些是可以放在编译时提前完成的。vue 2.0+ 已经在这方面做了不少的改进:分离了编译时和运行时、提供函数组件等,可以预见,vue 2.0的性能将有很大的提升。





作者:Coffce
来源:51CTO
目录
相关文章
|
1月前
|
JavaScript 数据可视化
vue-cli学习一:vue脚手架的 vue-cli2和vue-cli3版本 创建vue项目,vue的初始化详解
这篇文章介绍了如何使用vue-cli 2和3版本来创建Vue项目,并详细说明了两者之间的主要区别。
95 5
vue-cli学习一:vue脚手架的 vue-cli2和vue-cli3版本 创建vue项目,vue的初始化详解
|
1月前
|
算法 数据处理 Android开发
掌握安卓性能优化的秘诀:电池寿命与运行效率的提升
【10月更文挑战第6天】 本文深入探讨了安卓应用开发中的性能优化技巧,重点分析了影响电池寿命和运行效率的关键因素,并提供了针对性的优化策略。通过代码优化、资源管理、后台任务处理等方法,开发者可以显著提升应用的续航能力和流畅度。同时,结合具体案例,展示了如何在实际开发中应用这些技巧,确保应用在各种场景下都能保持高效运行。本文旨在为安卓开发者提供实用的性能优化指导,助力其打造更优质的应用体验。
50 2
|
16天前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
22天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
30 5
|
21天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
42 3
|
29天前
|
程序员 开发工具 Android开发
Android|WebView 禁止长按,限制非白名单域名的跳转层级
如何限制 WebView 仅域名白名单网址能随意跳转,并禁用长按选择文字。
34 2
|
1月前
|
存储 缓存 监控
Vue.js 九个性能优化技巧
【10月更文挑战第16天】Vue.js 性能优化是一个持续的过程,需要我们不断地探索和实践。通过合理使用上述九个技巧,并结合具体的项目需求和性能指标,我们可以不断地提高 Vue.js 应用的性能和用户体验。
|
1月前
|
存储 缓存 网络协议
5个Android性能优化相关的深度面试题
本文涵盖五个Android面试题及其解答,包括优化应用启动速度、内存泄漏的检测与解决、UI渲染性能优化、减少内存抖动和内存溢出、优化网络请求性能。每个问题都提供了详细的解答和示例代码。
28 2
|
1月前
|
存储 缓存 JavaScript
Vue 有哪些提高性能的优化技巧
【10月更文挑战第7天】 在 Vue 应用开发中,性能优化至关重要。本文介绍了十大优化技巧,包括数据结构优化、组件化设计、虚拟 DOM 优化、事件处理、数据绑定、图片优化、网络请求、代码优化、服务端渲染及其他技巧,帮助提升应用性能和用户体验。
25 1
|
1月前
|
监控 测试技术 Android开发
掌握安卓性能优化的关键策略
【10月更文挑战第7天】 在移动应用开发领域,性能优化是一项至关重要的任务。本文将探讨安卓应用性能优化的重要性、关键策略以及实际操作建议,帮助开发者提升应用的用户体验和竞争力。通过深入浅出的方式,我们将从背景介绍到具体实践,全面解析安卓性能优化的各个维度。
下一篇
无影云桌面