Skip to content

Commit

Permalink
Update performance.md
Browse files Browse the repository at this point in the history
  • Loading branch information
wanganxp committed Apr 16, 2020
1 parent 59bd178 commit aec69f0
Showing 1 changed file with 28 additions and 29 deletions.
57 changes: 28 additions & 29 deletions docs/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@

###### 视图层详解

h5和小程序平台,以及app-vue,视图层是webview。而app-nvue的视图层是基于weex改造的原生视图
h5和小程序平台,以及app-vue,视图层是webview。而app-nvue的视图层是基于weex改造的原生渲染视图

在iOS上,所有人都只能使用iOS提供的webview。它有一定的浏览器兼容问题,iOS版本不同,它的表现有细微差异。
关于webview,在iOS上,只能使用iOS提供的Webview(默认是WKWebview)。它有一定的浏览器兼容问题,iOS版本不同,它的表现有细微差异(一般可忽略)

Android上小程序大多自带了一个几十M的chromium webview,而App端没办法带这么大体积的三方包,所以App端使用了Android system webview,而系统webview跟随手机不同而有差异
Android上小程序大多自带了一个几十M的chromium webview,而App端没办法带这么大体积的三方包,所以App端默认使用了Android system webview,这个系统webview跟随手机不同而有差异。当然App端也支持使用腾讯X5引擎,此时可以在Android端统一视图层

所以uni-app的js基本没有不同手机的兼容问题(因为js引擎自带了),而视图层的css,在app-vue上会有手机浏览器的css兼容问题。所以在app-vue的场景中尽量不要使用太新的css语法,除非你不打算支持低端机
所以uni-app的js基本没有不同手机的兼容问题(因为js引擎自带了),而视图层的css,在app-vue上使用系统webview时会有手机浏览器的css兼容问题。此时或者不要用太细的css语法,或者集成腾讯x5引擎

###### 逻辑层和视图层分离的利与弊

Expand All @@ -40,61 +40,60 @@ iOS还好,但Android低端机上,每次通信都要耗时几十毫秒。平
1. 连续高帧率绘制canvas动画,会发现还不如webview内部绘制流程
2. 视图层滚动、跟手操作,不停反馈给逻辑层,js再处理逻辑并通知视图层做对应更新。此时会发现交互不跟手或卡

不管app-vue/小程序,还是app-nvue,都有相同的问题
不管小程序还是app,不管app-vue还是app-nvue,都有这个两层通信损耗的问题

解决这类问题,在webview渲染和原生渲染引用了不同的做法
解决这类问题,在webview渲染和原生渲染引用了不同的做法

- webview渲染的视图层

在app-vue和微信小程序上,提供了一种运行于视图层的专属js,微信叫做wxs,uni-app也沿用了这个名称
在app-vue和微信小程序上,提供了一种运行于视图层的专属js,微信叫做[wxs](https://uniapp.dcloud.io/frame?id=wxs)

微信里对wxs限制较多,只能实现有限的功能,app端(尤其是v3编译器下)则没有限制
wxs中可以监听手势,以uni ui的swiperAction组件为例,手指拖动,侧边的列表菜单项要跟手滑出,此时就需要使用wxs才能实现流畅效果。还有插件市场里一些自定义下拉刷新的插件,通过wxs实现了更高的性能体验

wxs中可以监听手势,以uni ui的swiperAction组件为例,手指拖动,侧边的列表菜单项要跟手滑出,此时就需要使用wxs才能实现流畅效果
uni-app支持把wxs编译到微信小程序、App和H5中

至于canvas动画,微信的canvas是原生的,无法运用wxs操作,且一样有通信折损,所以绘制动画的性能不佳。而uni-app的app-vue的canvas是webview的,并且支持wxs操作,开发者可以在普通js中传递数据和指令给wxs,在wxs里绘制动画,将不再有通信折损,实现更流畅的效果(app端需v3编译器)
微信里对wxs限制较多,只能实现有限的功能。app端提供了更强大的[renderjs](https://uniapp.dcloud.io/frame?id=renderjs),并兼容到H5平台。

比如canvas动画,微信的canvas无法通过wxs操作,js不停绘制canvas动画因通信折损而无法流畅。uni-app的app-vue里的canvas对象设计在webview视图层的,通过renderjs可以在视图层直接操作canvas动画,将不再有通信折损,实现更流畅的效果,详见:[renderjs](https://uniapp.dcloud.io/frame?id=renderjs)

- 原生渲染的视图层

在app-nvue里,折损一样存在。包括react native也有这个问题。weex发明了一套bindingx机制,可以在js里传一个表达式给原生,由原生解析后根据指令操作视图层,这个技术在uni-app里也可以使用。
在app-nvue里,逻辑层和视图层的折损一样存在。包括react native也有这个问题。所以也千万别以为原生渲染就多么高级。

weex提供了一套[bindingx](https://uniapp.dcloud.io/use-weex?id=nvue-%e9%87%8c%e4%bd%bf%e7%94%a8-bindingx)机制,可以在js里一次性传一个表达式给原生层,由原生层解析后根据指令操作原生的视图层,避免反复跨层通信。这个技术在uni-app里也可以使用。

bindingx作为一种表达式,它的功能不及js强大,但基本的手势监听、动画还是可以实现的,比如uni ui的swiperAction组件在app-nvue下运行时会自动启用bindingx,以实现流畅跟手。
bindingx作为一种表达式,它的功能不及js强大,但手势监听、动画还是可以实现的,比如uni ui的swiperAction组件在app-nvue下运行时会自动启用bindingx,以实现流畅跟手。

###### app-vue和小程序的数据更新,分页面级和组件级

对于复杂页面,更新某个区域的数据时,需要把这个区域做成组件,这样更新数据时就只更新这个组件,否则会整个页面的数据更新,造成点击延迟卡顿。
这就是自定义组件编译模式的特点。

比如微博长列表页面,点击一个点赞图标,赞数要立即+1,此时这个点赞按钮一定要做成组件。否则这个+1会引发页面级所有数据的更新
比如微博长列表页面,点击一个点赞图标,赞数要立即+1,此时这个点赞按钮一定要做成组件。否则这个+1会引发页面级所有数据的从js层向视图层的同步

app-nvue和h5不存在此问题。造成差异的原因是小程序目前只提供了组件差量更新的机制,不能自动计算所有页面差量。

#### 优化建议

##### 使用自定义组件模式

使用自定义组件模式,在manifest中配置自定义组件模式(HBuilderX1.9起新建项目默认即为自定义组件模式)。
##### App如果不是v3模式,请改为v3编译模式

在复杂页面中,页面中嵌套大量组件,如果是非自定义组件模式,更新一个组件会导致整个页面数据更新。而自定义组件模式则可以单独更新一个组件的数据。

在App端,除了上述好处,自定义组件模式还新增了一个独立的js引擎,加快启动速度、减少js阻塞。

之前的非自定义组件模式已经不再推荐,如果你的应用还是非自定义组模式,请尽快升级。
详见:[https://ask.dcloud.net.cn/article/36599](https://ask.dcloud.net.cn/article/36599)

##### 避免使用大图

页面中若大量使用大图资源,会造成页面切换的卡顿,导致系统内存升高,甚至白屏崩溃。

尤其是不要把多张大图缩小后显示在一个屏幕内,比如上传图片前选了数张几M体积的照片,然后缩小在一个屏幕中展示多张几M的大图,非常容易白屏崩溃。

对大体积的二进制文件进行base64,也非常耗费资源。

##### 优化数据更新

``uni-app`` 中,定义在 data 里面的数据每次变化时都会通知视图层重新渲染页面。 所以如果不是视图所需要的变量,可以不定义在 data 中,可在外部定义变量或直接挂载在vue实例上,以避免造成资源浪费。
``uni-app`` 中,定义在 data 里面的数据每次变化时都会通知视图层重新渲染页面。所以如果不是视图所需要的变量,可以不定义在 data 中,可在外部定义变量或直接挂载在vue实例上,以避免造成资源浪费。

##### 长列表
- 长列表中如果每个item有一个点赞按钮,点击后点赞数字+1,此时点赞组件必须是一个单独引用的组件,才能做到差量数据更新。否则会造成整个列表数据重载。(要求自定义组件模式)
- 长列表中如果每个item有一个点赞按钮,点击后点赞数字+1,此时点赞组件必须是一个单独引用的组件,才能做到差量数据更新。否则会造成整个列表数据重载。
- 长列表中每个item并不一定需要做成组件,取决于你的业务中是否需要差量更新某一行item的数据,如没有此类需求则不应该引入大量组件。(点击item后背景变色,属于css调整,没有更新data数据和渲染,不涉及这个问题)
- app端nvue的长列表应该使用list组件,有自动的渲染资源回收机制。vue页面使用页面滚动的性能,好于使用scroll-view的区域滚动。uni ui封装了uList组件,强烈推荐开发者使用,避免自己写的不好产生性能问题。
- app端nvue的长列表应该使用list组件,有自动的渲染资源回收机制。vue页面使用页面滚动的性能,好于使用scroll-view的区域滚动。uni ui封装了uList组件,在app-nvue下使用了list组件,在其他环境使用页面滚动,自动适配,强烈推荐开发者使用,避免自己写的不好产生性能问题。
- 如需要左右滑动的长列表,请在HBuilderX新建uni-app项目选新闻模板,那是一个标杆实现。自己用swiper和scroll-view做很容易引发性能问题。

##### 减少一次性渲染的节点数量
Expand All @@ -111,7 +110,7 @@ app-nvue和h5不存在此问题。造成差异的原因是小程序目前只提
* 监听 scroll-view 组件的滚动事件时,不要实时的改变 scroll-top/scroll-left 属性,因为监听滚动时,视图层向逻辑层通讯,改变 scroll-top/scroll-left 时,逻辑层又向视图层通讯,这样就可能造成通讯卡顿。
* 注意 onPageScroll 的使用,onPageScroll 进行监听时,视图层会频繁的向逻辑层发送数据;
* 多使用css动画,而不是通过js的定时器操作界面做动画
* 如果是canvas里做跟手操作,建议使用web-view组件。web-view里的页面没有逻辑层和视图层分离的概念,自然也不会有通信折损。
* 如需在canvas里做跟手操作,app端建议使用renderjs,小程序端建议使用web-view组件。web-view里的页面没有逻辑层和视图层分离的概念,自然也不会有通信折损。

##### 优化页面切换动画

Expand All @@ -121,7 +120,7 @@ app-nvue和h5不存在此问题。造成差异的原因是小程序目前只提
##### 优化背景色闪白

* 如果页面背景是深色,在vue页面中可能会发生新窗体刚开始动画时是灰白色背景,动画结束时才变为深色背景,造成闪屏。这是因为webview的背景生效太慢的问题。此时需将样式写在 ``App.vue`` 里,可以加速页面样式渲染速度。``App.vue`` 里面的样式是全局样式,每次新开页面会优先加载 ``App.vue`` 里面的样式,然后加载普通 vue 页面的样式。
* 还可以在pages.json的globalStyle->style->app-plus->background下配置全局背景色
* app端还可以在pages.json的页面的style里单独配置页面原生背景色,比如在globalStyle->style->app-plus->background下配置全局背景色
```json
"style": {
"app-plus": {
Expand All @@ -137,9 +136,9 @@ app-nvue和h5不存在此问题。造成差异的原因是小程序目前只提

##### 优化启动速度

* 工程代码越多,包括背景图和本地字体文件越大,对App的启动速度有影响,应注意控制体积。<image>组件引用的前景图不影响性能。
* 工程代码越多,包括背景图和本地字体文件越大,对小程序启动速度有影响,应注意控制体积。<image>组件引用的前景图不影响性能。app端在v3以前也存在和小程序一样的问题,但v3起解决了这个问题
* App端的 splash 关闭有白屏检测机制,如果首页一直白屏或首页本身就是一个空的中转页面,可能会造成 splash 10秒才关闭,可参考此文解决[https://ask.dcloud.net.cn/article/35565](https://ask.dcloud.net.cn/article/35565)
* App端使用自定义组件模式时启动速度更快,首页为nvue页面时启动速度更快
* App端使用v3编译器,首页为nvue页面时,并设置为[fast启动模式](https://ask.dcloud.net.cn/article/36749),此时App启动速度最快。
* App设置为纯nvue项目(manifest里设置app-plus下的renderer:"native"),这种项目的启动速度更快,2秒即可完成启动。因为它整个应用都使用原生渲染,不加载基于webview的那套框架。

##### 优化包体积
Expand Down

0 comments on commit aec69f0

Please sign in to comment.