多语言展示
当前在线:1730今日阅读:99今日分享:20

小程序白屏问题和内存解决方法

在开发小程序应用中,QA发现过几次页面白屏的情况,苦于难易复现和调试,故想对小程序白屏问题进行一番探究,寻求解决方法,分享给大家。
工具/原料

小程序官方开发者文档

脚本执行环境及组件
1

从小程序官方开发者文档得知,微信小程序运行在三端:iOS(iPhone/iPad)、Android和用于调试的开发者工具。三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的

2

在 iOS 上,小程序逻辑层的 javascript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的,环境有 iOS8、iOS9、iOS10

3

在 Android 上,旧版本,小程序逻辑层的 javascript 代码运行中 X5 JSCore 中,视图层是由 X5 基于 Mobile Chrome 53/57 内核来渲染的

4

新版本,小程序逻辑层的 javascript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile Chrome 53 内核来渲染的

5

在 开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium 60 Webview 来渲染的

WKWebView
1

在Apple公司的开发者文档网站上,有对WKWebView进行介绍,简单来说,WKWebView是一个为app内置浏览器渲染交互式网页内容的组件,用于替换老版本的UIWebView组件[2]。不管是UIWebView,还是WKWebView,它们都属于IOS WebView。我们可以把WebView理解为手机操作系统的一个系统级的组件。不管是手机内置的浏览器,还是其他app,比如微信等,只要你想呈现交互式的网页内容,都可以调用WebView去完成这件事情。Android WebView亦是如此

2

我们都知道浏览器有两个重要的引擎:渲染引擎(rendering engine,也称layout engine,即上面提到的排版引擎,后续为了方便,统一描述为渲染引擎)和JS引擎。其中渲染引擎负责解析网页内容,计算显示方式,输出至显示设备。JS引擎则负责解析JavaScript语言,实现网页的动态交互效果。最开始时渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎,即浏览器内核就是该浏览器采用的渲染引擎,主要参考X5内核调研报告。

3

现在,我们再回过头来看一下Mobile Chrome 53/57,或者Mobile Chrome 53,其实它的内核还是从WebKit上演化而来。绕了这么远,只为一句话:小程序就是运行在WebView之上。那么我们的初衷,研究小程序白屏问题,其实就是在探究WebView白屏问题。如果要更详细一点,那就是WKWebview、Android WebView白屏的原因。

WKWebview白屏原因与解决方案
1

关于WKWebview白屏,网上罗列的常见原因大致有以下几种:1.内存占用比较大时,WebContent Process 会 crash,从而出现白屏现象。2.URL网址无效或者含有中文字符。3.WKWebview刚推出时,在IOS8.0~8.2会偶尔出现白屏4.由于滚动组件嵌套的结构,不刷新的问题。

2

针对原因3,解决的方案是判断IOS系统版本,小于8.2的使用UIWebView。如果站在小程序开发者的角度,这个跟我们好像没有关系。小程序是个平台,我们在这个平台上开发我们的小程序应用,如果小程序也有这个问题,那只能由小程序团队去解决这件事情。还有,比如原因4,我们该嵌套还是得嵌套,有问题也是小程序团队去解决。至于原因2,如果是小程序原生开发的话,页面间的跳转URL包含中文也是能正常跳转的,这个应该是小程序内部兼容了。但是原因1,这个跟我们就有很大的关系了,比如我们定义了大量的变量,使用完了却没有释放,那么这部分内存在小程序销毁之前会被一直占用。再比如我们在某一刻操作了某个比较大的变量,可能在短时间内,内存使用量也会飙升。同样的,对于导致Android WebView白屏的问题,绝大部分也只能由小程序团队去解决。这样一来,从开发小程序应用的前端角度来说,我们能够把握的是尽量避免由于内存使用紧张导致的部分WebView被回收而出现的白屏问题。至此,我们研究的小程序白屏问题,可以转向对小程序内存优化的研究。

3

下面总结一下平时开发过程中可能会导致内存警告的操作:使用大图片和长列表图片。根据小程序团队分析过的大部分案例,大图片和长列表图片的使用,都会引起WKWebview被回收。其中长列表页图片是指页面包含数目较大的列表,每个列表里面又引用了图片。

4

随意定义变量,由于小程序的机制而又没有得到释放。以下四种场景下定义的变量,即使离开当前页面,变量也不会被回收:定义在Page构造器外层的全局变量。

5

定义在data内部的数据。

6

定义在Page内部,类data数据。

7

挂载到getApp().globalData上的数据。

8

假如我们在testvar页面定义了上述变量,由testvar通过navigateTo跳转到下一个页面otherpage,在页面otherpage里面我们可以通过getCurrentPages()获取页面testvar的引用,进而获取里面的变量。通过navigateTo打开新页面,上一个页面进入页面栈,并且该页面只是hide,并不是unload[11]。小程序框架的页面栈最多可支持10层页面。设想一下,那些具有复杂交互的页面,每层页面都附带了众多的数据,甚至包含很多图片,再考虑多层页面并存的问题,那内存使用量将是很可观的。在页面栈里面的页面unload之前,都会造成持续的内存占用。

9

短时间内大数据操作。假设在某个时间点,我们需要对接口返回的大量数据进行操作,可能会造成瞬时的内存占用。

10

列表数据的持续累加,导致某个数据异常大。设想一下,假如我们的列表页有很多条数据,每经过一次分页请求,我们就把新的数据concat到已有的数据之上,久而久之,这条数据可能会变成巨无霸,逐渐侵蚀我们的内存。

注意事项
1

针对原因1中的大图片,我们就可以适当压缩压缩。如果不能再压了,或者图片必须这么大,还有单个图片本来都不大。

2

针对原因2,我们需要结合实际的业务场景,对那些用完就可以丢弃的,不需要伴随页面整个生存周期存在的变量,就不要用那四种方式去定义数据。

3

针对原因3,我们可以尽量和接口开发方即速应用协商,通过分页或其他方式来避免接口一次返回大量的数据。

推荐信息