评论

app.onLaunch与page.onLoad异步问题

解决app.onLaunch与page.onLoad异步问题

问题:

相信很多人都遇到过这个问题,通常我们会在应用启动app.onLaunch() 去发起静默登录,同时我们需要在加载页面的时候,去调用一个需要登录态的后端 API 。由于两者都是异步,往往page.onload()调用API的时候,app.onLaunch() 内调用的静态登录过程还没有完成,从而导致请求失败。

解决方案:

1. 通过回调函数

// on app.js
App({
    onLaunch() {
      login()
       // 把hasLogin设置为 true
        .then(() => {
         this.globalData.hasLogin = true;
          if (this.checkLoginReadyCallback) {
            this.checkLoginReadyCallback();
          }
       })
       // 把hasLogin设置为 false
        .catch(() => {
         this.globalData.hasLogin = false;
       });
    },
});

// on page.js
Page({
    onLoad() {
      if (getApp().globalData.hasLogin) { // 登录已完成
            fn() // do something
      } else {
            getApp().checkLoginReadyCallback = () => {
              fn()
            }
      }
    },
});


⚠️注意:这个方法有一定的缺陷(如果启动页中有多个组件需要判断登录情况,就会产生多个异步回调,过程冗余),不建议采用。




2. 通过Object.defineProperty监听globalData中的hasLogin值


// on app.js
App({
    onLaunch() {
      login()
       // 把hasLogin设置为 true
        .then(() => {
         this.globalData.hasLogin = true;
       })
       // 把hasLogin设置为 false
        .catch(() => {
         this.globalData.hasLogin = false;
       });
    },
   // 监听hasLogin属性
    watchfunction (fn{
        var obj = this.globalData
        Object.defineProperty(obj, 'hasLogin', {
          configurabletrue,
          enumerabletrue,
          setfunction (value{
            this._hasLogin = value;
            fn(value);
          },
          getfunction () {
            return this._hasLogin
          }
        })
    },
});

// on page.js
Page({
    onLoad() {
      if (getApp().globalData.hasLogin) { // 登录已完成
            fn() // do something
      } else {
            getApp().watch(() => fn())
      }
    },
});

3. 通过beautywe的状态机插件(项目中使用该方法)


// on app.js
import { BtApp } from '@beautywe/core/index.js';
import status from '@beautywe/plugin-status/index.js';
import event from '@beautywe/plugin-event/index.js';

const app = new BtApp({
    onLaunch() {
      // 发起静默登录调用
      login()

      // 把状态机设置为 success
        .then(() => this.status.get('login').success())

      // 把状态机设置为 fail
        .catch(() => this.status.get('login').fail());
    },
});
// status 插件依赖于 beautywe-plugin-event
app.use(event());
 
// 使用 status 插件
app.use(status({
  statuses: [
    'login'
  ],
}));

// 使用原生的 App 方法
App(app);


// on page.js
Page({
    onLoad() {
      // must 里面会进行状态的判断,例如登录中就等待,登录成功就直接返回,登录失败抛出等。
      getApp().status.get('login').must().then(() => {
        // 进行一些需要登录态的操作...
      })
    },
});


具体实现


具体实现可以参考我的商城小程序项目

项目体验地址:体验

代码:代码

最后一次编辑于  2021-05-20  
点赞 8
收藏
评论

4 个评论

  • Api调用师
    Api调用师
    2022-01-10

    楼主你可以试试这个终极解决方案,更香:https://developers.weixin.qq.com/community/develop/article/doc/00002ac57208f0e7335d111f156013

    2022-01-10
    赞同 1
    回复 2
  • 老魏
    老魏
    发表于小程序端
    2021-05-20

    2021-05-20
    赞同 1
    回复
  • Jia
    Jia
    2022-01-17

    这可以用来监听wx.cloud.init吗?我试了第一和二的方法都不能用。我的小程序用户可以直接分享链接页面,发现app.onLaunch wx.cloud.init运行了page.onLoad后面。

    不好意思大家中文不好,希望你们理解我的问题。

    2022-01-17
    赞同
    回复 1
    • Jia
      Jia
      2022-01-17
      解决了,我globalData里加了isInitialized,然后直链接的页面有个条件检查globalData.isInitialized,如果false,在页面里运行wx.cloud.init(普通打开方式在app.js)
      2022-01-17
      回复
  • 曹孟良
    曹孟良
    2021-09-22

    老棒了

    2021-09-22
    赞同
    回复
登录 后发表内容