从dom变化可以看出,调用navigateTo相当于新打开一个webview加载另一个页面视图,随着打开的页面越来越多,内存就比较吃紧。这也是为什么小程序对打开页面数量有限制的原因。从图中可能也看出了,为啥多加载了一个pageframe.html的webview,这个是干什么用的?后面会说到它的作用。
视图层页面的实现我们在写小程序页面视图时,貌似并不关心webview中的html结构,这些都是小程序底层帮我们实现, 我们只需要写页面ui和业务逻辑即可。下面我们来看看view视图层小程序帮我们做了什么。先来看一下视图层pageframe.html的模板:
其中,模板中的注释占位符经过后台服务处理会注入不同js脚本,主要js内容:
<!-- deviceinfo -->: 暂时无用的占位符,会被空字符串""替换
<!-- jsdebug -->: 提供视图层的WeixinJSBridge模拟实现以及一些事件的处理如enablePullDownRefresh,其对应的js内容为extensions/pageframe/index.js.
<!-- plugincode -->: 小程序插件相关的代码,若小程序使用插件则会注入
<!-- wxmlcode -->: 调用wcc可执行命令生成的小程序注册所有页面wxml对应的js脚本内容
<!-- wxsscode -->: 调用wcss可执行命令生成的js脚本内容,提供注入css到页面的js方法;该内容会提前注入全局的css。
<!-- wxappcode -->: 小程序当前视图页面相关的配置json内容以及wxml和wxss转换为js的内容,可在控制台输入__wxAppCode__看相关信息
<!-- vendorlist -->: 小程序为视图层注入的基础库功能,包括WAWebview.js、WARemoteDebug.js和hls.js
视图层页面实现技术细节本节来详细介绍下小程序视图层实现的一些技术细节
视图层快速打开原理首先看一下小程序官网页面层级准备小节描述的一段内容:
wx.navigateTo会创建一个新的页面层级,对于每一个新的页面层级,视图层都需要进行一些额外的准备工作。在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页。除此以外,每当一个页面层级被用于渲染页面,微信都会提前开始准备一个新的页面层级,使得每次调用wx.navigateTo都能够尽快展示一个新的页面。
正如上文提到的,我们在打开pages/logs/logs视图页面时,发现dom中多加载了一个__pageframe__/pageframe.html的视图层,其模板内容正如上一节描述的。这个视图层的作用正是为了小程序提前为一个新的页面层准备的。
小程序每个视图层页面内容都是通过pageframe.html模板来生成的,包括小程序启动的首页;下面来看看小程序为快速打开小程序页面做的技术优化:
首页启动时,即第一次通过pageframe.html生成内容后,后台服务会缓存pageframe.html模板首次生成的html内容。
非首次新打开页面时,页面请求的pageframe.html内容直接走后台缓存
非首次新打开页面时,pageframe.html页面引入的外链js资源(如上图所示)走本地缓存
这样在后续新打开页面时,都会走缓存的pageframe的内容,避免重复生成,快速打开一个新页面。
视图层新打开页面流程其实在小程序开发者工具实现中,在创建每个视图层页的webview时,都会为其绑定了onLoadCommit事件(它会在页面加载完成后触发,包含当前文档的导航和副框架的文档加载)。初始时webview的src会被指定为空页面地址:${global.proxyPort}/aboutblank?${c},其中c为对应webview的id。webview从空页面到具体页面视图的过程如下:
空页面地址webview加载完毕后执行事件中的reload方法,即设置webview的src为pageframe地址:${global.proxyPort}/__pageframe__/pageframe.html。
加载完成后,设置其src为pageframe.html:
新的src内容加载完成后再次触发onLoadCommit事件但根据条件不会执行reload方法。