在 onInit 请求首屏主数据

基础库 3.160.12 及以上版本开始支持Page.onInit

大部分小程序,需要发起至少一次网络请求并调用setData,才能完成整个页面的最终渲染。如果能优化该环节,页面的渲染时间将会大大缩短。

回顾一下我们在性能优化的原理和手段中所介绍的小程序启动流程,可以发现无论是把主数据请求放在App.onLaunch里还是Page.onLoad里,都会存在一些难以解决问题:

  1. 如果在App.onLaunch中请求主数据,那么每个页面的请求逻辑都需要在放在App的生命周期中,这样不仅造成了逻辑的耦合,也将一定程度影响初始数据initData的发送,继而拖慢渲染层的初次渲染。
  2. 如果在Page.onLoad中请求主数据,那么必须要等到渲染层完成firstRender之后才能请求主数据,时机比较晚。

onInit 简介

小程序提供一种页面级别的生命周期Page.onInit

该生命周期的执行时机介于App.onLaunchPage.onLoad之间。具体的执行时机可参考下图,小程序是在setInitData之后立即执行Page.onInit()

在 onInit 请求首屏主数据 - 图1

如果把主数据请求从 Page.onLoad 转移到 Page.onInit 中,将极大提升小程序的页面加载性能。

开发者可以在onInit中向服务器请求数据,并执行setData。图中展示了setData的两种时机,同时应注意:

  1. 如果开发者setData发出的时机早于渲染线程的 FCP ,那么在onLoad中将能获取到本次setData的视图信息。
  2. 如果setData晚于 FCP ,那么onLoad中将获取不到本次setData的视图信息。

由于App.onShow是依赖客户端通知逻辑线程的,所以Page.onInit不一定会在首次 App.onShow之后执行。
可确定的前后顺序是:App.onLaunch-> Page.onInit ->Component.created->Component.attached->Page.onLoad

如何使用 onInit

尽量将页面的业务数据请求放在Page.onInit中。

  • JS
  1. function getData(param) {
  2. return new Promise((resolve, reject) => {
  3. swan.request({
  4. url: 'xxx',
  5. success: res => resolve(res)
  6. });
  7. });
  8. }
  9. Page(
  10. // 使用一个标记位,确保只请求一次主数据
  11. hasRequest: false
  12. data: {
  13. value: ''
  14. },
  15. onInit(param) {
  16. if (!this.hasRequest) {
  17. this.hasRequest = true;
  18. getData(param).then(res => {
  19. this.setData({
  20. value: res.data
  21. });
  22. })
  23. }
  24. },
  25. onLoad(param) {
  26. if (!this.hasRequest) {
  27. this.hasRequest = true;
  28. getData(param).then(res => {
  29. this.setData({
  30. value: res.data
  31. });
  32. })
  33. }
  34. }
  35. );

使用建议

  1. 不能进行任何依赖视图层的操作,包括且不限于:selectComponentselectAllComponentsswan.createSelectorQueryswan.createMapContextswan.createCameraContextswan.createCanvasContext等;
  2. 由于并非所有版本的基础库都支持此生命周期,开发者可以参考上述代码片段,增加兼容逻辑;
  3. 如果您的小程序在逻辑线程初始化阶段存在较大瓶颈,那么使用Page.onInit可能不会有明显效果。建议从减少动态库和插件的使用、减少App.onLaunch耗时等角度进行优化。

onInit 的收益

此处以百度知道、百度百科和宝宝知道小程序为例使用Page.onInit进行了优化,上屏时长均有明显提升。

在 onInit 请求首屏主数据 - 图2

以下是三个小程序把主数据请求从Page.onLoad迁移到Page.onInit后,获取到的收益:

小程序收益(单位:ms)
百度知道210
百度百科100
宝宝知道150