页面切换优化
页面切换的性能影响用户操作的连贯性和流畅度,是小程序运行时性能的一个重要组成部分。
1. 页面切换的流程
要想优化页面切换的性能,有必要先简单了解下小程序页面切换的过程。页面切换流程如图所示:
当切换的目标页面已加载完成时(例如:路由类型为 navigateBack,或 switchTab 到一个已加载到页面)`,不需要进行「视图层页面初始化」和「目标页面渲染」,「逻辑层页面初始化」也会较为简化,如下图所示:
1.1 触发页面切换
页面切换的流程,从用户触发页面切换开始。
页面切换可能由以下几类操作触发:
- 小程序 API 调用:开发者根据用户操作,调用
dlt.navigateTo
、dlt.navigateBack
、dlt.redirectTo
、dlt.reLaunch
、dlt.switchTab
等 API。 - 用户点击原生 UI 触发:例如点击 tabBar(自定义 tabBar 除外)、点击左上角「返回首页」按钮、点击系统返回键或左滑返回等。
1.2 视图层页面初始化
小程序视图层的每个页面都是由独立的 WebView 渲染的,因此页面切换时需要一个新的 WebView 环境。视图层页面初始化主要会做以下事情:
- 创建 WebView
- 注入视图层的小程序基础库
- 注入页面代码
为了降低视图层页面初始化的耗时,在页面渲染完成后,通常会进行必要的预加载供页面切换时使用。预加载主要会做以下事情:
- 创建 WebView
- 注入视图层的小程序基础库
如果页面切换过快,或预加载的环境被回收,则需要在页面切换时重新创建环境。
如果页面切换时有预加载好的环境,可以大大降低页面切换的耗时。
当切换的目标页面已加载完成时,不需要进行本阶段。
1.4 逻辑层页面初始化
完成 WebView 创建后,客户端会向基础库派发路由事件。
基础库收到事件后会进行逻辑层的页面初始化,包括触发上一个页面的 onHide/onUnload
、页面组件树初始化、更新页面栈并生成初始数据发送到视图层,并依次触发目标的 onLoad
, onShow
生命周期。
基础库收到事件的时间对应 PerformanceEntry(route) 中的 navigationStart,对应 PerformanceEntry(firstRender) 的开始时间。
当切换的目标页面已加载完成时,不需进行页面组件树初始化和初始数据的发送,且不会触发目标页面的 onLoad。
1.5 目标页面渲染
页面切换的目标页面不存在时,会触发页面的首次渲染。
在完成视图层代码注入,并收到逻辑层发送的初始数据后,结合从初始数据和视图层得到的页面结构和样式信息,小程序框架会进行页面渲染,并触发页面的 onReady 事件。
视图层渲染完成,触发页面 onReady 事件的时间,对应 PerformanceEntry(firstRender) 的结束时间。
当切换的目标页面已加载完成时,不需要进行本阶段。
1.6 页面切换动画
页面渲染完成后,客户端会进行页面切换的动画(如:从右向左推入页面)。如果页面初始化和渲染的时间超过固定时间,为避免用户以为页面无响应,页面会提前推入。
页面推入动画完成的时间,对应 PerformanceEntry(route) 的结束时间。
2. 如何优化页面切换
2.1 首屏渲染优化
页面首屏渲染是页面切换耗时的重要组成部分,优化手段可以参考启动性能优化中首屏渲染优化部分。
2.3 提前发起数据请求
在一些对性能要求比较高的场景下,当使用 JSAPI 进行页面跳转时(例如 dlt.navigateTo),可以提前为下一个页面做一些准备工作。页面之间可以通过 数据状态管理 思路,通过将数据保存到全局 App 或者自定义管理实例,进行数据共享分发。
例如,在页面跳转时,可以同时发起下一个页面的数据请求,而不需要等到页面 onLoad 时再进行,从而可以让用户更早的看到页面内容。尤其是在跳转到分包页面时,从发起页面跳转到页面 onLoad 之间可能有较长的时间间隔,可以加以利用。