[uni-app]让app.onLaunch与page.onLoad/onShow顺序执行的实践
相信大家肯定都遇到过题目中所说的那种需求,在 app.onLaunch
中获取一些信息,在 Page
中使用。然而这些生命周期钩子都是异步执行的,并没有特定的执行顺序。这就需要开发者自己控制生命周期钩子的执行顺序。
小程序设计得已经比较糟糕,性能低的同时还有许多不可知的奇怪的 bug (关于性能,他们推出了 SkyLine,暂时没有使用过)。而 uni-app 在小程序的基础上,还要兼容更多不同厂家的小程序,还要能够编译成各端代码,莫名其妙的 bug 就更多了。
关于题目中的需求,我尝试了 2 种方法,一是回调函数法,就是在 app.onLaunch
执行完毕后执行一个回调函数,用来初始化页面;二是 Promise.resolve 法,就是在 Page.onLoad
中使用 await
执行一个函数,将其 Promise 的 resovle
回调函数存储起来,这样一来,await
之后的代码就处于等待状态;在 app.onLaunch
的最后调用那个 resolve
,结束 Page.onLoad
中 await
的等待状态。
遗憾的是,虽然网上有很多成功案例,但经过尝试,截止到本文发表的时刻,在最新的 HBuilder X 环境下,这两种方法并不能保证 app.onLaunch
与 page.onLoad/onShow
先后执行。
除了这两种方法,网上还有诸多神奇的解决方案,但我并没有尝试。最后我使用了最“笨”的方法,但感觉是最稳妥的办法,那就是 setInterval
大法!
setInterval
平常总是被嫌弃,就连实现倒计时,也要用 setTimeout
代替它。没想到最后它解决了我的问题,而且非常稳健!
思路非常简单:
在 app.globalData
中声明一个变量,比如叫 launched
,初始值是 false
,用来表示 app.onLaunch
是否执行完毕。然后,在 app.onLaunch
的最后,把它设置为 true
。
与此同时,页面中的 onLoa
d 或者 onShow
中设置一个 interval
,一旦检查到 getApp().globalData.launched === true
,则取消定时器,并执行初始化。
由于 uni-app 使用的是 Vue,所以可以在 main.js
中添加全局的 mixin
来执行 onLoad/onShow
,若符合条件,则在 onLoad/onShow
中执行页面中约定好的方法,例如,若 mixin
中的 onLoad
检测到小程序已经执行完 onLaunch
,则进一步检查当前页面中是否有约定好的方法,如 _onLoad
,若有则执行。这样,就不用在每个页面中的 onLoad/onShow
中写重复的代码了。
由于比较简单,就不上代码了。
以前觉得写小程序简单,因为只需要在小程序那“简单的”框架中写代码,所能做的东西有限。现在终于明白,想要实现一些在 H5 中普通的功能,小程序需要更多的尝试。
End