Jan 29, 2021

微信小程序页面中获取 app.js 中的异步数据

微信小程序的 app.js 和刚进入时首次展示的 page.js 将同步执行,因此有些时候在 page.js 中需要获取 app.js 中异步数据时,就需要一些奇淫巧技。在微信小程序的初始 Demo 中展示了页面中获取 app.js 中用户信息的逻辑,本质是在 app 实例中添加了一个回调:

// app.js // 获取用户信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { wx.getUserInfo({ success: res => { this.globalData.userInfo = res.userInfo _**if (this.userInfoReadyCallback) { this.userInfoReadyCallback(res) }**_ } }) } } }) // pages/index/index.js if (app.globalData.userInfo) { this.setData({ userInfo: app.globalData.userInfo, hasUserInfo: true }) } else { _**app.userInfoReadyCallback = res => { this.setData({ userInfo: res.userInfo, hasUserInfo: true }) }**_ }

但当有很多页面都需要获取 app.js 中的用户信息时,就需要每个页面给 app 实例添加回调函数,这样无疑会增加很多冗余代码,以及额外的维护成本。因此我们可以进行简单的封装,给 app.js 添加一个统一的回调或异步函数,每个页面都只需要调用这一个方法即可。

App({ globalData: { // ===== User Info ===== isUserInfoInited: false, userInfoListeners: [], isRegistered: false, userInfo: null, }, onLaunch() { this.initUserInfo(); }, async initUserInfo() { // 自行实现获取用户信息的方法,可异步可同步 const userInfo = await Auth.login(); this.globalData.userInfo = userInfo.userInfo; this.globalData.isRegistered = userInfo.isRegistered; // 将之前页面暂存的回调方法一一执行 this.globalData.isUserInfoInited = true; this.globalData.userInfoListeners.forEach(listener => { listener({ userInfo: this.globalData.userInfo, isRegistered: this.globalData.isRegistered }); }); }, // 通过回调方式获取用户信息。有则返回,无则暂存回调方法,等用户信息加载完毕后统一执行 getUserInfo(cb) { if (this.globalData.isUserInfoInited) { cb({ userInfo: this.globalData.userInfo, isRegistered: this.globalData.isRegistered }); } else { this.globalData.userInfoListeners.push(cb); } }, // 对上面的回调方式进行 Promise 化,可以异步获取用户信息 getUserInfoAsync() { return new Promise(resolve => this.getUserInfo(resolve)); } });

在页面中使用时:

const app = getApp(); // 回调方式 Page({ onLoad() { app.getUserInfo(({ userInfo, isRegistered }) => { // userInfo 一定有值 }); } }); // 异步方式 Page({ async onLoad() { const { userInfo, isRegistered } = await app.getUserInfoAsync(); // userInfo 一定有值 } });