白屏问题与小程序记忆研究
在小程序应用的开发中,QA发现了几个白屏页面的案例,很难重现和调试,所以想探索小程序的白屏问题。
根据小程序的官方开发者文档,微信小程序运行在三个终端上:iOS(iPhone/iPad)、Android和开发者工具进行调试。脚本执行环境和第三方呈现非本机组件的环境不同[1]:
在iOS上,小程序逻辑层的javascript代码运行在JavaScriptCore中,视图层由WKWebView渲染,环境为iOS8、iOS9、iOS10。在安卓上,老版本,小程序逻辑层的javascript代码运行在X5 JSCore中,视图层由基于Mobile Chrome 53/57内核的X5渲染。新版本中,小程序逻辑层的javascript代码运行在V8中,视图层由基于Mobile Chrome 53内核的自研XWeb引擎渲染。在开发工具上,小程序逻辑层的javascript代码运行在NW.js中,视图层由Chrome60WebView渲染。先说说WKWebView,Mobile Chrome 53/57,Mobile Chrome 53。
在苹果公司的开发者文档网站上,介绍了WKWebView。简单来说,WKWebView是一个为app内置浏览器渲染交互式网页内容的组件,用来替代UIWebView组件的旧版本[2]。无论是UIWebView还是WKWebView,都属于IOS WebView。我们可以将WebView视为移动操作系统的系统级组件。无论是手机内置的浏览器,还是微信等其他应用,只要你想呈现互动的网页内容,都可以调用WebView来完成这个任务。安卓WebView也是如此[3]。
现在我们可以在IOS上调用WKWebView WebView,那么什么是Mobile Chrome 53/57或者Android上的Mobile Chrome 53,这两者和WebView有什么关系呢?我们可以把Mobile Chrome 53/57理解为安卓537版本的Chrome,其中537指的是Chrome的布局引擎采用的WebKit内核版本,具体可以参考谷歌Chrome版本历史[4]。需要指出的是,53/57是否是537在这里值得怀疑,也没有找到有效的参考资料,但这应该对我们的研究没有影响,可以忽略。这里介绍两个概念:布局引擎和WebKit内核。接下来,简单介绍布局引擎和WebKit内核。
我们都知道浏览器有两个重要的引擎:渲染引擎(也称为布局引擎)和JS引擎。渲染引擎负责分析网页内容,计算显示模式,并输出到显示设备。JS引擎负责解析JavaScript语言,实现网页的动态交互效果。起初,渲染引擎和JS引擎之间没有明确的区别。后来JS引擎越来越独立,内核倾向于只参考渲染引擎,即浏览器内核就是浏览器使用的渲染引擎,主要参考X5内核研究报告[5]。在下面的讨论中,浏览器内核仅指渲染引擎。
什么是WebKit内核?这要追溯到WebKit的历史。1998年,自由软件社区KDE开发了HTML排版引擎KHTML和JavaScript解析引擎KJS,这是现代浏览器的两个重要引擎。苹果的开发者唐梅尔顿在2001年开始了基于KDE的网络工具包项目。起初,WebKit只是KDE的翻版,我们可以理解为WebKit是基于KDE的fork的一个分支。后来在WebKit项目中,KHTML被命名为WebCore,KJS被命名为JavaScriptCore,主要参考维基百科[6]。至此,我们可以回答,至少对于苹果产品来说,浏览器内核是WebKit,也就是渲染引擎使用WebKit内核。
Webkit项目是苹果为了开发自己的浏览器而发起的项目。谷歌在开发Chrome浏览器的同时,也建立了Chrome项目。在Chromium项目中,JavaScript解析引擎使用了谷歌自己开发的著名的V8引擎,渲染引擎使用了WebKit内核。到2013年7月,Chromium项目用Blink引擎取代了渲染引擎,并在Chrome28及更高版本上采用了[4][7]。Blink引擎是WebKit项目中基于WebCore的Google fork的一个分支[8][9]。我们可以用一张图片将KDE、网络工具包和Chromium串联起来:
现在,我们再回过头来看一下Mobile Chrome 53/57,或者Mobile Chrome 53,其实它的内核还是从WebKit上演化而来。绕了这么远,只为一句话:小程序就是运行在WebView之上。那么我们的初衷,研究小程序白屏问题,其实就是在探究WebView白屏问题。如果要更详细一点,那就是WKWebview、Android WebView白屏的原因。
关于WKWebview白屏,网上罗列的常见原因大致有以下几种:
- 内存占用比较大时,WebContent Process 会 crash,从而出现白屏现象。
- URL网址无效或者含有中文字符。
- WKWebview刚推出时,在IOS8.0~8.2会偶尔出现白屏
- 由于滚动组件嵌套的结构,不刷新的问题。
针对原因3,解决的方案是判断IOS系统版本,小于8.2的使用UIWebView。如果站在小程序开发者的角度,这个跟我们好像没有关系。小程序是个平台,我们在这个平台上开发我们的小程序应用,如果小程序也有这个问题,那只能由小程序团队去解决这件事情。还有,比如原因4,我们该嵌套还是得嵌套,有问题也是小程序团队去解决。至于原因2,如果是小程序原生开发的话,页面间的跳转URL包含中文也是能正常跳转的,这个应该是小程序内部兼容了。但是原因1,这个跟我们就有很大的关系了,比如我们定义了大量的变量,使用完了却没有释放,那么这部分内存在小程序销毁之前会被一直占用。再比如我们在某一刻操作了某个比较大的变量,可能在短时间内,内存使用量也会飙升。同样的,对于导致Android WebView白屏的问题,绝大部分也只能由小程序团队去解决。
这样一来,从开发小程序应用的前端角度来说,我们能够把握的是尽量避免由于内存使用紧张导致的部分WebView被回收而出现的白屏问题。至此,我们研究的小程序白屏问题,可以转向对小程序内存优化的研究。
下面总结一下平时开发过程中可能会导致内存警告的操作:
使用大图片和长列表图片。根据小程序团队分析过的大部分案例,大图片和长列表图片的使用,都会引起WKWebview被回收[10]。其中长列表页图片是指页面包含数目较大的列表,每个列表里面又引用了图片。
随意定义变量,由于小程序的机制而又没有得到释放。以下四种场景下定义的变量,即使离开当前页面,变量也不会被回收:
定义在Page构造器外层的全局变量。
定义在data内部的数据。
定义在Page内部,类data数据。
挂载到getApp().globalData上的数据。
假如我们在testvar页面定义了上述变量,由testvar通过navigateTo跳转到下一个页面otherpage,在页面otherpage里面我们可以通过getCurrentPages()获取页面testvar的引用,进而获取里面的变量。通过navigateTo打开新页面,上一个页面进入页面栈,并且该页面只是hide,并不是unload[11]。小程序框架的页面栈最多可支持10层页面。设想一下,那些具有复杂交互的页面,每层页面都附带了众多的数据,甚至包含很多图片,再考虑多层页面并存的问题,那内存使用量将是很可观的。在页面栈里面的页面unload之前,都会造成持续的内存占用。
短时间内大数据操作。假设在某个时间点,我们需要对接口返回的大量数据进行操作,可能会造成瞬时的内存占用。
列表数据的持续累加,导致某个数据异常大。设想一下,假如我们的列表页有很多条数据,每经过一次分页请求,我们就把新的数据concat到已有的数据之上,久而久之,这条数据可能会变成巨无霸,逐渐侵蚀我们的内存。
所幸的是,上述这些可能造成内存大量占用的操作,我们是可以避免或者优化的。
- 针对原因1中的大图片,我们就可以适当压缩压缩。如果不能再压了,或者图片必须这么大,还有单个图片本来都不大,但是列表太多造成引用的图片太多怎么办呢?好,这个可以暂时先放下,在后续的讨论中再提对应的解决方案。
- 针对原因2,我们需要结合实际的业务场景,对那些用完就可以丢弃的,不需要伴随页面整个生存周期存在的变量,就不要用那四种方式去定义数据。
- 针对原因3,我们可以尽量和接口开发方协商,通过分页或其他方式来避免接口一次返回大量的数据。
- 针对原因4,本质的原因是持续的分页请求导致新的数据不断追加到已有的数据之上,那么这种场景,我们就需要对已有的部分数据进行舍弃。舍弃哪些已有的数据,需要一个原则。设想一下有这样一个场景,我们进入列表页list,我们定义了listData用来存放每次分页请求过来的数据。第一页的数据过来了,listData仅仅包含第一页数据。第二页数据过来了,我们把新数据concat到第一页上,此时,listData就包含了第一、第二两个页面的数据。第三页的数据过来了,listData就包含前三个页面的数据。现在我们不妨停下来想想,目前我们给用户呈现的是第三页的数据,第一页的数据处于不可见的状态,既然不可见,为何不把它丢弃?如果用户往上滑动,需要呈现第一页的数据时,我们可以再请求第一页的数据。listData丢弃部分数据,会及时反馈到view层,view层部分节点也会随之销毁,这样App Service层和view层占用的部分内存都会得到释放。当然,我们提出的这种方案,就是为了解决持续的分页请求导致新的数据不断追加到已有的数据之上的问题,至于要不要采用,采用了什么场景下进行已有数据丢弃,丢弃哪些数据,这些都要结合实际的业务进行评估和权衡。
希望大家进行批评和指正!
版权声明:白屏问题与小程序记忆研究是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。