小程序页面生命周期和应用生命周期分别有哪些?
简化版
小程序应用生命周期主要有 onLaunch、onShow、onHide;页面生命周期主要有 onLoad、onShow、onReady、onHide、onUnload。应用生命周期关注整个小程序,页面生命周期关注单个页面的创建、显示、渲染、隐藏和销毁。
详细版
应用生命周期:
onLaunch:小程序初始化时触发,整个生命周期通常只执行一次。onShow:小程序进入前台时触发。onHide:小程序进入后台时触发。
页面生命周期:
onLoad:页面加载时触发,适合读取路由参数、初始化数据。onShow:页面显示时触发,页面每次回到前台都会执行。onReady:页面首次渲染完成后触发。onHide:页面隐藏时触发。onUnload:页面卸载时触发。
面试中要特别区分 onLoad 和 onShow。onLoad 通常只在页面创建时执行一次,onShow 会在页面每次展示时执行,适合做刷新、重新拉取状态等逻辑。
完整版教学
一、应用生命周期
应用生命周期定义在 app.js 中,它描述的是整个小程序从启动到进入后台的过程。
onLaunch 适合做全局初始化,例如读取本地缓存、初始化监控、获取启动参数、准备全局配置。它通常只执行一次。
onShow 表示小程序进入前台。用户从聊天窗口、扫码、分享卡片、后台切回时,都可能触发它。这里适合处理需要恢复的状态,比如检查登录态、刷新全局消息数量。
onHide 表示小程序进入后台。这里适合做轻量收尾,比如暂停定时器、记录停留时间、保存必要状态。
二、页面生命周期
页面生命周期定义在页面的 JS 文件中。
onLoad(options) 在页面创建时执行,可以拿到页面路径参数。比如详情页根据 id 请求详情数据,通常在这里做。
onShow() 在页面显示时执行。一个页面被跳转回来、从后台恢复、从 tab 切回来,都可能触发它。
onReady() 在页面首次渲染完成后执行。如果需要操作选择器查询、创建动画上下文,通常放在这里更合适。
onHide() 在页面隐藏时执行,比如跳转到其他页面或切后台。
onUnload() 在页面销毁时执行,比如关闭当前页、重定向、页面栈被清理。
三、常见误区
很多同学会把所有初始化都放到 onShow,结果页面每次回来都重复请求接口,造成闪烁和性能浪费。
更合理的做法是:
- 首次进入必须执行的逻辑放
onLoad。 - 每次展示都要刷新的逻辑放
onShow。 - 与页面渲染节点有关的逻辑放
onReady。 - 清理定时器、取消监听放
onHide或onUnload。
四、面试追问与工程落地
面试官可能会问:“从 A 页面跳到 B 页面,再返回 A,A 的哪些生命周期会触发?”
通常 A 跳到 B 时,A 触发 onHide;从 B 返回 A 时,A 触发 onShow,但不会重新触发 onLoad,因为 A 页面还在页面栈中。
如果用 redirectTo 或页面被销毁,则会触发 onUnload,下次进入会重新 onLoad。
工程中常见做法是给页面状态加“是否首次加载”的标记,避免 onShow 中重复执行重初始化逻辑。
五、页面栈变化与生命周期时间线
首次打开页面 A 时,核心顺序可记为 onLoad → onShow → onReady;其中 onReady 只表示首次渲染完成,不代表网络请求已经返回。A 使用 navigateTo 打开 B 时,A 通常 onHide,B 执行首次生命周期;B navigateBack 后卸载,A 再次 onShow。
首次 A:A.onLoad → A.onShow → A.onReady
A 打开 B:A.onHide → B.onLoad → B.onShow → B.onReady
B 返回 A:B.onUnload → A.onShow
| 路由动作 | 当前页面 | 目标页面 | 返回后的特点 |
|---|---|---|---|
navigateTo | onHide | 首次加载 | 原页面仍在栈中 |
redirectTo | onUnload | 首次加载 | 当前页被替换 |
navigateBack | onUnload | 已有页面 onShow | 不重新 onLoad |
switchTab | 关闭非 tab 页 | tab 页显示 | tab 页可能已存在 |
reLaunch | 原页面卸载 | 新根页面加载 | 页面栈重新建立 |
六、异步竞态、组件生命周期与清理
生命周期回调不是请求事务边界。假设 A 在 onLoad 发请求 R1,用户切换筛选后又发 R2;若 R2 在 100ms 返回、R1 在 500ms 返回,旧 R1 可能覆盖新结果。可给请求加递增序号,只有返回序号等于当前序号时才更新页面,或在 API 支持时取消旧请求。
页面暂时隐藏时,是否取消任务取决于业务:返回后仍可复用的详情请求可以保留,高频定位、定时器和事件监听应在 onHide 暂停,在 onShow 恢复;页面销毁时则在 onUnload 做最终释放。初始化函数要设计成幂等,避免每次 onShow 都重复注册监听器。
自定义组件还有 created、attached、ready、detached 等 lifetimes,以及感知所在页面显示/隐藏的 pageLifetimes。页面与组件的生命周期职责不同:页面管理路由和页面级请求,组件管理自身资源,不能只依赖页面替所有组件清理。
易错点:
onHide是“仍在页面栈里但不可见”,onUnload才是“实例被销毁”;这决定了回来时是恢复还是重建。
七、常见误区与追问
- 误区:
onReady触发代表接口数据已经全部加载完成。 它只代表页面首次渲染完成,异步请求有自己的完成时间。 - 误区:每次进入页面都会重新执行
onLoad。 栈中已有页面返回时通常只执行onShow,销毁后重新进入才会onLoad。 - 误区:所有数据刷新都应该写在
onShow。 这会在返回、切 tab、前后台切换时重复请求,应区分首次初始化和每次可见都需刷新。 - 追问:A 打开 B 再返回,A 为什么保留滚动位置?
navigateTo只是隐藏 A,页面实例仍在栈中,返回时恢复并触发onShow。 - 追问:
onHide和onUnload的清理策略有何区别? 前者适合暂停可恢复任务,后者要释放与实例绑定的资源和监听。 - 追问:如何避免旧请求覆盖新请求? 使用请求序号、Abort/取消能力或比较查询条件,只接纳当前页面状态对应的结果。
- 追问:组件如何感知页面切到后台再回来? 使用组件的
pageLifetimes,同时在detached做最终解绑。
八、加强记忆
生命周期用“创建、可见、首渲染、隐藏、销毁”串起来:首次是 onLoad → onShow → onReady,栈内返回通常只再走 onShow,被替换或关闭才走 onUnload。业务上把一次性初始化、每次可见刷新、渲染后操作和资源清理分开,并用序号或取消机制处理异步竞态;组件资源还要在自己的 lifetimes 中闭环。