相信大家肯定都遇到过题目中所说的那种需求,在 app.onLaunch 中获取一些信息,在 Page 中使用。然而这些生命周期钩子都是异步执行的,并没有特定的执行顺序。这就需要开发者自己控制生命周期钩子的执行顺序。

小程序设计得已经比较糟糕,性能低的同时还有许多不可知的奇怪的 bug (关于性能,他们推出了 SkyLine,暂时没有使用过)。而 uni-app 在小程序的基础上,还要兼容更多不同厂家的小程序,还要能够编译成各端代码,莫名其妙的 bug 就更多了。

关于题目中的需求,我尝试了 2 种方法,一是回调函数法,就是在 app.onLaunch 执行完毕后执行一个回调函数,用来初始化页面;二是 Promise.resolve 法,就是在 Page.onLoad 中使用 await 执行一个函数,将其 Promise 的 resovle 回调函数存储起来,这样一来,await 之后的代码就处于等待状态;在 app.onLaunch 的最后调用那个 resolve,结束 Page.onLoadawait 的等待状态。

遗憾的是,虽然网上有很多成功案例,但经过尝试,截止到本文发表的时刻,在最新的 HBuilder X 环境下,这两种方法并不能保证 app.onLaunchpage.onLoad/onShow 先后执行。

除了这两种方法,网上还有诸多神奇的解决方案,但我并没有尝试。最后我使用了最“笨”的方法,但感觉是最稳妥的办法,那就是 setInterval 大法!

setInterval 平常总是被嫌弃,就连实现倒计时,也要用 setTimeout 代替它。没想到最后它解决了我的问题,而且非常稳健!

思路非常简单:
app.globalData 中声明一个变量,比如叫 launched,初始值是 false,用来表示 app.onLaunch 是否执行完毕。然后,在 app.onLaunch 的最后,把它设置为 true
与此同时,页面中的 onLoad 或者 onShow 中设置一个 interval,一旦检查到 getApp().globalData.launched === true,则取消定时器,并执行初始化。

由于 uni-app 使用的是 Vue,所以可以在 main.js 中添加全局的 mixin 来执行 onLoad/onShow,若符合条件,则在 onLoad/onShow 中执行页面中约定好的方法,例如,若 mixin 中的 onLoad 检测到小程序已经执行完 onLaunch,则进一步检查当前页面中是否有约定好的方法,如 _onLoad,若有则执行。这样,就不用在每个页面中的 onLoad/onShow 中写重复的代码了。

由于比较简单,就不上代码了。

以前觉得写小程序简单,因为只需要在小程序那“简单的”框架中写代码,所能做的东西有限。现在终于明白,想要实现一些在 H5 中普通的功能,小程序需要更多的尝试。


End

标签: uni-app