DCloud_heavensoft
DCloud_heavensoft
  • 发布:2014-06-30 05:21
  • 更新:2019-07-29 10:20
  • 阅读:325146

提升HTML5的性能体验系列之一 避免切页白屏

分类:HTML5+

本系列文章是针对5+App的,与uni-app无关。uni-app不存在切换白屏问题

提升HTML5的性能体验系列文章目录导航:

窗体切换白屏的现实问题

HTML5的性能比原生差很多,比如切页时白屏、列表滚动不流畅、下拉刷新和上拉翻页卡顿。
在低端Android手机上,很多原生App常用的功能和体验效果都很难使用HTML5技术模拟。
我们首先来看第一个问题,如何避免切页白屏。

浏览器的页面在切换时,由于其页面加载机制,在跳转到下一个页面时,先要请求联网、载入页面代码、构建dom、渲染,最后才显示出来。
在最终结果渲染完毕前,会出现几十毫秒甚至数秒的白屏。原生App是没有这个问题的。
虽然使用SPA单页应用模型,即ajax+div切换也可以避免白屏,但把所有页面写在一个SPA页面里,简单几个页面还行。但页面多了手机上也跑不起来,初始化非常慢,首页必然白屏,而且工程大了代码那个乱。。。被坑过的人自然知道。

解决窗体切换白屏的方案

标准HTML5无法解决,我们就使用扩展的手段。
HTML5+是一套增强HTML5的规范,它可以用JS调用几十万原生API。
想要解决切页白屏这个问题,需要使用plus.webview类来做MPA多页应用(不是SPA单页应用)。
plus.webview类是对原生的webview对象的js化封装,使用js可以操作webview。
解决白屏的原理是:把每个页面当作一个webview,但用js来控制它就像控制div一样。动画时通过原生的view动画飘webview进来而不是通过css动画飘div进来
同时webview之间相互独立,不会出现SPA下不同页面js和css冲突的问题。

通过操作webview来避免切页白屏,有几种常见的做法:

1、动画先飘不会白屏的原生title进来

既然webview加载慢,转场动画会白屏。原生view加载快,不会白屏。那么能不能使用原生view呢,或者至少动画时先飘一个原生view的title进来,也不会整屏白屏。
HBuilder7.2起,提供了plus.nativeObj.View,也就是原生的view对象(以下简称nview),可以使用js向原生的view直接写字、绘图(注意是原生view不是webview)。
从HBuilder8.8起,优化了nview和Webview的关系,为Webview引入了titleNView和subNView,是从属于Webview的原生界面。titileNView也称ntitle,进一步对title的原生化做了简化了操作,在plus.webview的style里,可以配置titleNView,如下示例:

plus.webview.create('new.html', 'new', {'titleNView':{'backgroundcolor':'#FFFFFF','titletext':'标题栏','titlecolor':'#FF0000'}});

这样创建webview时,会自带一个原生的title,文字、颜色、是否有返回箭头、分割线这些都可以设置,见http://html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewTitleNViewStyles。还可以通过getTitleNView()方法得到一个nview对象,自由的向上面写字、绘图、处理点击响应。参考nview文档http://html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View
如果只是简单修改,比如修改title文字,也可以通过重设TitleNView的style来实现:
plus.webview.currentWebview().setStyle({titleNView:{titleText:'new text'}})

在mui框架中,进一步简化封装了mui.openWindowWithTitle()方法,参考http://dev.dcloud.net.cn/mui/window/#openWindowWithTitle

上面title有了,中间空白处可以先转个plus.nativeUI.waiting的原生雪花或显示加载中,这样转场时就不会飘白屏了。
一般本地页面加载都很快,转场动画300毫秒结束时,页面也渲染出来了。

另外提供几个让HTML页面渲染快的方法

  • 页面渲染尽量不用js做,想要渲染快,就直接写HTML和css渲染,js渲染的界面显示更慢。
  • 少用padding、margin,尽量写简单的代码,让页面一次渲染到位,而不是反复触发重绘。
  • 减少图片尺寸,不要使用背景图(最常见的性能问题均来自于此)

理解了titleNView,我们再来看subnview。
同理,subnview也是原生渲染的view,它可用于更大面积的原生渲染。
在流应用里的唯品会中,商品详情界面的加载速度那么快,就是因为使用了subnview。参考视频http://v.qq.com/x/page/k05051mc143.html
一般业务有titleNView就够了,追求极致体验的业务可以使用subnview。
所谓追求极致,就是要求在100毫秒渲染,动画期间就要完成联网和渲染。即使原生应用,大部分业务也是在动画完成后才渲染界面的。
使用subnview要在页面里大量通过js构造界面,不太直观。HBuilder8.3.3起,新增了wap2app项目,其中引入了nview模板,新建一个nview文件,可以使用类vue的方式开发,参考http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12757。后续会把nview模板引入到5+应用开发中。

延伸:既然有nview,那是不是可以使用nview做完整界面,废除webview?类似react native那样。
DCloud一直遵循的是HTML5+的规范和理念,即不推翻HTML,而是在HTML做的不好的地方强化补足。
即使在动画期间大量使用了subnview,但滚动后的完整的页面仍然应该是HTML的。
这样的解决方案即能满足用户体验要求,又能兼容好HTML5,是更好的解决方案。

早些年mui曾推荐使用过head和body分开载入的方案,此方案已废弃,由这里描述的原生title方案替代。

2、预加载html

既然HTML渲染慢,是否可以后台预加载,需要使用时直接动画进来?
当然是可以的。所谓预载,即后台预载新页面的HTML文件及资源,使用时直接调出这个已经创建好的webview。
尤其是从一个列表页面反复打开详情页面,仅仅是其中的数据不同,此时应该预载和复用详情Webview。
在Hello mui里有一个列表到详情的最佳实践示例,就是使用了这个思路,强烈建议大家在列表到详情时研究使用这个示例。文章参考http://ask.dcloud.net.cn/article/12575

只要服务器返回数据不拖后退,一样可以实现100毫秒渲染,动画期间完成联网和渲染。

预加载,由于不显示出来,并不会过多增加资源占用。(同时显示在屏幕上的webview不要超过3个,隐藏在后台的webview不要超过10个)
如果是list转到content,不同的item点击只是一个页面,完全可以使用预载。
但如果页面不同且较多,此时不建议预载太多Webview。后台预载太多webview需要耗很长,会抢cpu,此时用户如果在前台显示的Webview里操作比如滚动列表,会感觉到卡。

mui框架的窗体函数封装

mui框架为了简化窗体管理的工作,把一些常用的窗体模型做了简化封装。
但对于复杂的窗体切换,仍需开发者搞明白上面提到的窗体切换原理。
mui的init方法,通过参数封装了preload,这样就可以方便的预载webview。
mui的openWindow方法,封装了显示waiting,载入新页面,处理动画,关闭waiting等工作。
mui的openWindowWithTitle()方法,封装了原生title。
mui的back样式控制,自动封装了窗体的隐藏和关闭。
这些方法具体参考mui的js API

启动后首页的白屏

首页是没有预加载的概念的。
首页的控制基本都在manifest里进行。
有2个与启动白屏有关的manifest设置。
1.launchwebview
在launchwebview里可以配置首页的titlenview,以及使用subnview制作tab。
这样顶部和底部实际上是由原生引擎渲染的,可以迅速显示。
参考文章:基于subnview模式的原生tab

  1. splashscreen
    启动封面的图片如何关闭是在manifest里配置的。
    默认是在首页的webview的loaded事件发生后关闭。但又提供了若干选项。
    不管你的首页是白屏了还是觉得进入太慢了,都可以控制。
    在工程下manifest.json里找到plus、splashscreen节点,这里有event选项,可以配置是在哪个事件时close splash,默认是loaded,也可以配成titileUpdate、rendering、rendered。
    默认配置loaded事件是偏保守的,避免有的开发者首页代码写的不高效,导致白屏。
    如果你的首页代码效率高、渲染快,则推荐配置成titileUpdate事件。

还有一种手动控制splash关闭的技巧,如果splashscreen节点下的autoclose设置为false,即手动,可以在首页代码里写js控制封面图片的消失时机。
此时在首页合适的位置,比如说联网结束或业务上的其他时间点,调用js关闭封面图片,plus.navigator.closeSplashscreen();
但不管什么方法,5+引擎的splash显示时间不会超过6秒,如果6秒内开发者仍不能做到首页渲染,那么用户会看到白屏。

关于如何优化启动速度,可以参考这篇文章http://ask.dcloud.net.cn/article/571

5+动画详解

这篇文章详细描述了5+提供的各种原生动画的特点及优化技巧,是必读文章http://ask.dcloud.net.cn/article/225

Android5的动画花屏、分块渲染解决方案

如果你遇到了相关问题,可以参考http://ask.dcloud.net.cn/article/12837

后记

不管使用哪种方法,都要注意一点,手机App的HTML页面必须本身性能足够高。
这是老生常谈的问题,但现实中还是大量App因为这个问题而导致性能体验出问题。
编写干净整洁、一次渲染的页面非常重要。
现在太多开发者在研究模式、框架,让页面渲染要经历二次、甚至四五次重绘才能完成。在短短几百毫秒的动画期间,这么干要不让页面卡、要不让渲染慢。
dom层级简单点,不要嵌套太多。
减少css二次渲染,就是少用复杂的选择器,少用padding、margin这些会二次修正页面的css。
如果追求极致的话,那jquery、zepto这些框架也不要使用,手机上都是webkit引擎,直接写document的api操作dom即没有兼容问题又没有效率问题。

2018年8月,DCloud推出了uni-app,这个产品自动优化了预载、原生组件,如果你无法把HTML5+的app优化的足够好,不如直接使用uni-app。无需优化天然达到微信小程序水准。

130 关注 分享
旧情 小小雨 半杯可乐 hellojh wglhtml5 炭烧咖啡 HU 海洋 JSoon 飞越 Cp0204 fany Solomon 毒气 太空小行星 Aylchen jayeeliu 太阳光 仙人指路 哈根达斯 Mr丶Leo 水粑粑 龙七 wuweitiandian BruceAn Liosixer 注水豆芽 xinglongjian 飞一扬 atubo 随风如下 damdmen 拉链里的小怪兽 junyi igo44444 木子喵 zgnm2009 Hzuy 趴趴熊 七星端砚 ahwx1994 涛涛江水 qmit 小指一弹 ccfto 蔡繁荣 Tronyel 永恒菂诺儿 tosmaller moliu

要回复文章请先登录注册

道者

道者

可以将页面加载完,再进行跳转,基本也可以避免白屏现象
mui.openWindow(url,id,{
show:{
event:"loaded"//在当前页面加载,加载完在跳转
},
waiting:{
autoShow:true,//自动显示等待框,默认为true
title:'正在加载...'//等待对话框上显示的提示内容
}
})
},
将show的event参数设置为"loaded".
2019-07-29 10:20
g***@sina.com

g***@sina.com

https://github.com/gs-wenbing/mui-mall/
一款基于mui+vue的购物商城类APP
2019-07-26 15:58
k***@foxmail.com

k***@foxmail.com

集成方式太笨重 号称单页html5+却存在各种问题 一点都不灵活 兼容太差 有国企的风范
2019-06-27 15:34
r***@sina.com

r***@sina.com

学习了
2019-06-19 16:27
东方飞鱼

东方飞鱼

mark
2019-01-28 11:59
2***@qq.com

2***@qq.com

mui 再首页 列表 到最后再跳转到首页的时候 再重新打开列表页面就不重新数据怎么弄?
2018-01-03 20:16
Android_Yanbin

Android_Yanbin

回复 M***@qq.com :
这个问题可参考下这篇文章:http://ask.dcloud.net.cn/article/110
其中的plus节点下的waiting属性控制的就是启动界面是否显示系统等待框,true表示显示系统等待框,false表示不显示系统等待框,默认值为false。
2017-10-23 18:21
M***@qq.com

M***@qq.com

什么时候能够把安卓原生app+h5plus 混合开发模式下的io.dcloud.PandoraEntry 类处理下,让用户可以自定义app的欢迎页面,那是多么的美好,每次启动都在转圈圈,你们设计的时候考虑过吗?考虑过吗?考虑过吗?纠结了好几天,都快把百度和你们的文档翻完了,都没有找见有设置的地方,对得起我们开发者的心吗?难不成用户使用原生+H5集成的方式只能允许用户的app每次启动的时候转圈圈。。。你们不觉得很好笑吗?
2017-10-16 21:40
DCloud_heavensoft

DCloud_heavensoft (作者)

回复 亿朵云 :
这个不是预加载了,5+引擎在同时打开多个窗体后,在Android上有2层的栈保留机制,超过2层的老窗体,渲染资源也会自动回收。除非开发者手动设置了Webviewstyle里的render:always,强制不出栈。按你说的情况,a、b出栈并回收渲染资源了,c的渲染资源并未释放
2017-09-22 17:29
亿朵云

亿朵云

关于
预加载,由于不显示出来,并不会过多增加资源占用。(同时显示在屏幕上的webview不要超过3个,隐藏在后台的webview不要超过10个)
这一段

假设在页面A预加载了页面B、C、D,
那么由页面A mui.openWindow(B)
再由页面B mui.openWindow(C)
最后由C mui.openWindow(D)
显然,此时webview D是属于"显示在屏幕上的webview"
而mui.openWindow()并不会触发之前webview的hide事件
故此时
webview A、B、C是属于“隐藏在后台的webview”吗?
2017-09-21 05:53