小程序生命周期解析:App Lifecycle与Page Lifecycle的协同运作
小程序的生命周期是开发者构建稳定、高效应用的核心知识体系,其分为应用生命周期(App Lifecycle) 和页面生命周期(Page Lifecycle) 两个层级。两者通过嵌套式触发机制,共同管理小程序从启动到销毁的全流程状态变化。本文将结合具体场景与代码示例,深入解析两者的差异与协作逻辑。
一、应用生命周期(App Lifecycle):全局状态管理中枢
应用生命周期由App()构造器定义,负责管理小程序实例的全局状态,其核心函数包括:
1. onLaunch:初始化启动
-
触发时机:小程序首次启动时触发(仅一次),包括冷启动和热启动(如从后台恢复)。
-
典型场景:
- 获取用户授权信息(如
uni.login()获取code) - 初始化全局配置(如主题、缓存策略)
- 检查版本更新并提示用户
- 获取用户授权信息(如
-
代码示例:
javascript 1App({ 2 onLaunch(options) { 3 console.log('小程序启动,场景值:', options.scene); 4 // 静默登录 5 uni.login({ 6 success: (res) => { 7 if (res.code) { 8 // 发送code到服务器换取openid 9 } 10 } 11 }); 12 // 检查更新 13 if (wx.canIUse('getUpdateManager')) { 14 const updateManager = wx.getUpdateManager(); 15 updateManager.onCheckForUpdate((res) => { 16 if (res.hasUpdate) { 17 updateManager.onUpdateReady(() => { 18 wx.showModal({ 19 title: '更新提示', 20 content: '新版本已准备好,是否重启应用?', 21 success: (res) => { 22 if (res.confirm) updateManager.applyUpdate(); 23 } 24 }); 25 }); 26 } 27 }); 28 } 29 } 30}); 31
2. onShow:前台激活
-
触发时机:
- 小程序启动后进入前台
- 从后台切回前台(如用户返回微信聊天界面后重新打开小程序)
-
典型场景:
- 刷新用户活跃数据
- 检查网络状态并重连
- 恢复音乐/视频播放
-
代码示例:
javascript 1App({ 2 onShow(options) { 3 console.log('小程序进入前台,场景值:', options.scene); 4 // 统计用户活跃 5 uni.request({ 6 url: 'https://api.example.com/stats/active', 7 method: 'POST', 8 data: { timestamp: Date.now() } 9 }); 10 // 检查网络状态 11 uni.getNetworkType({ 12 success: (res) => { 13 if (res.networkType === 'none') { 14 uni.showToast({ title: '网络已断开', icon: 'none' }); 15 } 16 } 17 }); 18 } 19}); 20
3. onHide:后台休眠
-
触发时机:小程序从前台切至后台(如用户按Home键或切换至其他应用)
-
典型场景:
- 保存临时数据(如表单草稿)
- 清除定时器
- 暂停媒体播放
-
代码示例:
javascript 1App({ 2 onHide() { 3 console.log('小程序进入后台'); 4 // 保存购物车状态 5 const cart = uni.getStorageSync('cart') || []; 6 uni.setStorageSync('cart_backup', cart); 7 // 清除全局定时器 8 if (this.globalTimer) clearInterval(this.globalTimer); 9 } 10}); 11
4. onError:错误捕获
-
触发时机:发生脚本错误或API调用失败时
-
典型场景:
- 上报错误日志到服务器
- 提示用户重试
-
代码示例:
javascript 1App({ 2 onError(err) { 3 console.error('小程序错误:', err); 4 uni.request({ 5 url: 'https://api.example.com/error/report', 6 method: 'POST', 7 data: { 8 error: err.message, 9 stack: err.stack, 10 timestamp: Date.now() 11 } 12 }); 13 uni.showToast({ title: '服务异常,请稍后重试', icon: 'none' }); 14 } 15}); 16
二、页面生命周期(Page Lifecycle):单页状态管理单元
页面生命周期由Page()构造器定义,负责管理单个页面的加载、渲染、交互和销毁过程,其核心函数包括:
1. onLoad:页面加载
-
触发时机:页面初次加载时触发(仅一次)
-
典型场景:
- 获取路由参数(如
options.id) - 初始化页面数据
- 发起一次性数据请求
- 获取路由参数(如
-
代码示例:
javascript 1Page({ 2 onLoad(options) { 3 console.log('页面加载,参数:', options); 4 // 根据ID加载商品详情 5 if (options.id) { 6 this.loadProductDetail(options.id); 7 } 8 // 初始化表单数据 9 this.setData({ form: { name: '', phone: '' } }); 10 }, 11 loadProductDetail(id) { 12 uni.request({ 13 url: `https://api.example.com/products/${id}`, 14 success: (res) => { 15 this.setData({ product: res.data }); 16 } 17 }); 18 } 19}); 20
2. onShow:页面显示
-
触发时机:
- 页面初次加载完成后
- 从其他页面返回时
- 从后台切回前台时
-
典型场景:
- 刷新动态数据(如用户收藏状态)
- 恢复页面动画
- 统计页面访问
-
代码示例:
javascript 1Page({ 2 onShow() { 3 console.log('页面显示'); 4 // 刷新收藏状态 5 this.checkFavoriteStatus(); 6 // 恢复动画 7 if (this.animation) this.animation.play(); 8 }, 9 checkFavoriteStatus() { 10 const userId = uni.getStorageSync('userId'); 11 uni.request({ 12 url: `https://api.example.com/favorites/check?userId=${userId}&productId=${this.data.product.id}`, 13 success: (res) => { 14 this.setData({ isFavorite: res.data.isFavorite }); 15 } 16 }); 17 } 18}); 19
3. onReady:页面渲染完成
-
触发时机:页面初次渲染完成时触发(仅一次)
-
典型场景:
- 操作DOM节点(如获取Canvas上下文)
- 启动依赖布局的动画
-
代码示例:
javascript 1Page({ 2 onReady() { 3 console.log('页面渲染完成'); 4 // 获取Canvas上下文 5 const query = uni.createSelectorQuery().in(this); 6 query.select('#myCanvas') 7 .fields({ node: true, size: true }) 8 .exec((res) => { 9 const canvas = res[0].node; 10 const ctx = canvas.getContext('2d'); 11 // 绘制动画 12 this.animateCanvas(ctx); 13 }); 14 }, 15 animateCanvas(ctx) { 16 // 动画逻辑... 17 } 18}); 19
4. onHide:页面隐藏
-
触发时机:
- 跳转至其他页面时
- 切至后台时
-
典型场景:
- 保存页面状态(如表单输入)
- 暂停页面定时器
-
代码示例:
javascript 1Page({ 2 data: { form: { name: '', phone: '' } }, 3 onHide() { 4 console.log('页面隐藏'); 5 // 保存表单草稿 6 uni.setStorageSync('form_draft', this.data.form); 7 // 暂停定时器 8 if (this.timer) clearInterval(this.timer); 9 } 10}); 11
5. onUnload:页面销毁
-
触发时机:页面被完全卸载时触发(如调用
uni.redirectTo或uni.reLaunch) -
典型场景:
- 清理页面资源(如WebSocket连接)
- 取消事件监听
-
代码示例:
javascript 1Page({ 2 onUnload() { 3 console.log('页面销毁'); 4 // 清理WebSocket连接 5 if (this.socket) { 6 this.socket.close(); 7 this.socket = null; 8 } 9 // 移除全局事件监听 10 uni.offCustomEvent(this.handleCustomEvent); 11 } 12}); 13
三、生命周期协同机制:嵌套触发与状态传递
小程序生命周期的核心在于应用级与页面级的嵌套触发,其典型流程如下:
-
首次启动:
1App.onLaunch → App.onShow → Page.onLoad → Page.onShow → Page.onReady 2 -
页面跳转(A→B) :
1PageA.onHide → PageB.onLoad → PageB.onShow → PageB.onReady 2 -
返回上一页(B→A) :
1PageB.onUnload → PageA.onShow 2 -
切至后台:
1Page.onHide → App.onHide 2 -
切回前台:
1App.onShow → Page.onShow 2
四、最佳实践:生命周期的合理利用
-
数据初始化:
- 全局数据:在
App.onLaunch中加载 - 页面数据:在
Page.onLoad中加载
- 全局数据:在
-
性能优化:
- 避免在
onShow中发起耗时请求(可结合防抖机制) - 在
onHide/onUnload中及时清理资源
- 避免在
-
状态同步:
- 利用
App.globalData共享全局状态 - 通过路由参数传递页面间数据
- 利用
-
错误处理:
- 在
App.onError中统一捕获未处理异常 - 在页面中捕获具体业务错误
- 在
结语
小程序的生命周期体系通过应用级与页面级的分层设计,实现了全局状态与局部状态的解耦管理。开发者需深入理解各生命周期函数的触发时机与典型场景,结合具体业务需求合理编排代码逻辑,才能构建出高效、稳定的小程序应用。