一个小程序有很多页面,每个页面又有各自的线程、生命周期和功能逻辑。关于小程序的生命周期、页面之间的跳转有哪些特殊的地方呢? 很多关于小程序的文档内容被分散在各个地方,理解和使用起来还是需要查找,春哥团队小编南音给大家整理笔记如下:
小程序的启动
小程序启动过程
初次进入小程序的时候,微信客户端初始化好宿主环境,同时从网络下载或者从本地缓存中拿到小程序的代码包,把它注入到宿主环境。大概是这么个过程:
- 创建线程(渲染层和逻辑层),启动小程序。
- 载入基础库(WebView 基础库和 AppService 基础库)。
- 载入小程序业务代码(下载或者从本地缓存中拿到)。
- 使用
App() 注册程序实例。
为了让小程序业务代码能够调用 API 以及组件,就需要在启动小程序后先载入基础库,接着再载入业务代码。 由于所有小程序都需要注入相同的基础库,所以小程序的基础库会被提前内置在微信客户端。而基础库是热更新的,故一般等微信客户端携带上一个稳定版的基础库正式发布后,再进行新版本基础库的灰度和推送。
注册 App 实例
宿主环境提供了App() 构造器用来注册一个程序 App。App 实例是单例对象,在其他 JS 脚本中可以使用宿主环境提供的getApp() 来获取程序实例。
App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。
App() 函数用来注册一个小程序。接受一个Object 参数,其指定小程序的生命周期回调等。
onLaunch 小程序初始化完成时(全局只触发一次)触发onLaunch 回调。 在微信客户端中打开小程序有很多途径,对不同途径的打开方式,小程序有时需要做不同的业务处理。所以微信客户端会把打开方式带给onLaunch 和onShow 的调用参数options ,我们可以根据参数来判断一些进入方式,以及做对应的逻辑处理。
例如,我需要拿到从另外一个小程序跳转过来携带的信息,此时场景值应该是1037(参考场景值):
1 2 3 4 5 6 7 8 9 |
App({ // ... onShow: function(e) { if(e.scene === 1037){ const data = e.referrerInfo && e.referrerInfo.extraData; // 拿到对应的数据 const refAppid = e.referrerInfo && e.referrerInfo.appId; // 拿到对应的小程序appid } } }) |
onShow 小程序启动,或从后台进入前台显示时触发onShow 回调。通常我们用来处理数据和状态的更新。 小程序进入后台状态:当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁。
onHide 小程序从前台进入后台时触发onHide 回调。 小程序进入前台状态:当再次进入微信或再次打开小程序,又会从后台进入前台。
获取 App 实例
我们可以使用全局的getApp() 函数来获取到小程序 App 实例(在App() 内的函数中使用this 就可以拿到app 实例。)。
前面我们可以看到,App 的生命周期是由微信客户端根据用户操作主动触发的。故我们通过getApp() 获取实例之后,不应该私自调用生命周期函数。
具体的原理是什么呢?小程序的 JS 脚本是运行在 JsCore 的线程里,小程序的每个页面各自有一个 WebView 线程进行渲染,所以小程序切换页面时,小程序逻辑层的 JS 脚本运行上下文依旧在同一个 JsCore 线程中。
因此,App 构造器可以传递其他参数作为全局属性以达到全局共享数据的目的。
由于所有页面的脚本逻辑都跑在同一个 JsCore 线程,页面使用setTimeout 或者setInterval 的定时器,即使切换了页面,也需要自行清理定时器。可以选择:
- 在页面离开
onUnload 、onHide 等的时候自行清理
- 做全局的定时器管理(当然也还是需要关闭时清理)
说到页面之间的数据共享,我们也该来讲讲小程序里页面的启动。
小程序页面
页面生命周期
宿主环境提供了Page(Object) 构造器用来注册一个小程序页面,接受一个Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
注意:Object 内容在页面加载时会进行一次深拷贝,需考虑数据大小对页面加载的开销。
页面生命周期函数: onLoad(Object query) 页面加载时触发。一个页面只会调用一次,可以在onLoad 的参数中获取打开当前页面路径中的参数。
onShow() 页面显示/切入前台时触发。
onReady() 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
onHide() 页面隐藏/切入后台时触发。
onUnload() 页面卸载时触发。
和小程序实例的生命周期对比,其实页面也是有些相似。这里需要注意几点:
- 当前页面路径的参数获取,只能在
onLoad(query) 的query 参数中获取,无法在onShow() 中获取
onLoad 、onReady 和onUnload ,一个页面都只会调用一次
- 页面是卸载还是切换到后台,这些除了与小程序的后台切换有关系,还会与页面的跳转、切换逻辑有关系
- 下面我们就来看下页面的逻辑。
-
页面导航
我们知道,一个小程序会拥有多个页面。在小程序里会有页面的层级关系,例如通过wx.navigateTo 推入一个新的页面,在首页使用2次wx.navigateTo 后,页面层级会有三层:

获取页面栈
getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。 需要注意的是:
- 修改页面栈会导致路由以及页面状态错误
App.onLaunch 的时候 page 还没有生成,不能在这调用getCurrentPages()
-
但是其实不是每一次切换页面,都会被记录到页面栈里,我们看看页面导航的一些方法和行为:

关于导航 API 的几个补充点:
wx.navigateTo 和wx.redirectTo 只能打开非 TabBar 页面,wx.switchTab 只能打开 Tabbar 页面,wx.reLaunch 可以打开任意页面
- TabBar 页面指在 app.json 的 TabBar 字段定义的页面(客户端窗口的底部或顶部有 tab 栏可以切换页面)
- 跳转到 TabBar 页面,路径后不能带参数(注意,Tabbar 页面初始化之后不会被销毁)
- 调用页面路由带的参数可以在目标页面的
onLoad 中获取
-
页面层级准备
我们知道页面栈的表现,以及一些常见的导航方法,而小程序基础库也在页面层级做了些体验优化。
对于每一个新的页面层级,视图层都需要进行一些额外的准备工作:
- 在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页
- 每当一个页面层级被用于渲染页面,微信都会提前开始准备一个新的页面层级,减少每次新开页面的耗时
-
每个页面的准备都有三个阶段:
- 启动一个 WebView。
- WebView 中初始化基础库(此时还会进行一些基础库内部优化,以提升页面渲染性能)。
- 注入小程序 WXML 结构和 WXSS 样式(小程序能在接收到页面初始数据之后马上开始渲染页面)。
-
PS:wx.redirectTo 不会打开一个新的页面层级,而是将当前页面层级重新初始化。 页面的路由和跳转、切入方式,其实和用户的使用和交互紧紧相关,设计合理也是能大大提升用户体验的。
部分资料摘自小程序文档,如有不足或相似之处,欢迎联系我们。
|