# PageFrame
还记得在前面文章中我们寻找渲染层的时候,找到了个奇怪的webview。

pageFrame这个webview是干嘛的呢?我们这章节就来探索一下。
我们在写小程序页面视图时,貌似并不关心webview中的html结构,这些都是小程序底层帮我们实现,我们只需要写页面ui和业务逻辑即可。下面我们来看看view视图层小程序帮我们做了什么。先来看一下视图层pageframe.html的模板:

为了讲解便利,中间部分代码由标识进行替代。从上图上看来是不是和渲染层的HTML非常像。这个webview其实就是一个用来新渲染webview的模板。
我们已知在小程序中使用 WXML 文件描述页面的结构,WXSS 文件描述页面的样式,WXML文件会被编译为虚拟DOM,WXSS会被编译为js。那么每个独立的页面都会经过这样的编译,如何快速的生成webview,或者说如何快速的打开一个页面。会成为一个问题。我们有了虚拟DOM和样式描述表就可以渲染页面了吗。还远远不够。
先分析一下pageFrame的html结构中注入的js资源:
-
./__dev__/wxconfig.js:小程序默认总配置项,包括用户自定义与系统默认的整合结果。在控制台输入
__wxConfig可以看出打印结果
-
./__dev__/devtoolsconfig.js小程序开发者配置,包括
navigationBarHeight,标题栏的高度,状态栏高度,等等,控制台输入__devtoolsconfig可以看到其对应的信息

-
./__dev__/deviceinfo.js设备信息,包含
尺寸/像素点pixelRatio -
__dev__/jsdebug.jsdebug工具。
-
./__dev__/WAWebview.js渲染层底层基础库
-
./__dev__/hls.js优秀的视频流处理工具。
-
./__dev__/WARemoteDebug.js底层基础库调试工具
可以看到pageFrame注入的脚本与我们分析pages/index渲染层webview是一样的。正式因为pageFrame快速启动技术,就像一个工厂一样,可以快速生成webview的基础格式。在这其中pageFrame就是业务webview的模板。
我们继续往下分析,有一些不一样的地方。
<!-- wxappcode -->
可以发现pageFrame中包含一些注释的单词,这些注释的单词为注释占位符,如果你细心对比就会发现,在前面分析渲染层代码的时候,我们见到过这些注释占位符编译后的样子。
比如wxappcode.js在渲染层中为如下形式(老版本基础库)
<script src="./__dev__/wxappcode.js" chartset="UTF-8"></script>
或者是这样(新版本基础库)
无论新老版本,其中的代码都是一样的。我们先看一下内部结构。

文件中包含了所有页面的编译路径,这个编译路径有什么作用呢,小册后面章节virtualDOM章节中,编译WXML后生成的$gwx函数需要的参数就是这个路径。此文件中就进行了保存。
再接着看的话会看到WXSS章节讲到的编译后的WXSS,就跟我们在渲染层看到的一样,eval(setCssToHead....)。
内部记录的属性有:
decodePathName.json配置.wxml编译后的$gwx函数。$gwx函数会在virtualDOM章节重点讲解。.wxss编译后的eval函数。
这里就可以想象出来,如果小程序需要打开某个页面的时候,只需要从这里提取出页面特有的这几个属性,配合pageFrame模板就可以快速生成一个新的webview。
那么具体快速启动的方案是怎样的呢?我们继续探索
# 如何快速启动
我们看一下官方给予的一段描述:
在视图层内,小程序的每一个页面都独立运行在一个页面层级上。小程序启动时仅有一个页面层级,每次调用wx.navigateTo,都会创建一个新的页面层级;相对地,wx.navigateBack会销毁一个页面层级。 对于每一个新的页面层级,视图层都需要进行一些额外的准备工作。在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页。除此以外,每当一个页面层级被用于渲染页面,微信都会提前开始准备一个新的页面层级,使得每次调用wx.navigateTo都能够尽快展示一个新的页面。 页面层级的准备工作分为三个阶段。第一阶段是启动一个WebView,在iOS和Android系统上,操作系统启动WebView都需要一小段时间。第二阶段是在WebView中初始化基础库,此时还会进行一些基础库内部优化,以提升页面渲染性能。第三阶段是注入小程序WXML结构和WXSS样式,使小程序能在接收到页面初始数据之后马上开始渲染页面(这一阶段无法在小程序启动前执行)。
对于wx.redirectTo,这个调用不会打开一个新的页面层级,而是将当前页面层级重新初始化:重新传入页面的初始数据、路径等,视图层清空当前页面层级的渲染结果然后重新渲染页面。

我们对官方的这段描述进行一个解释:
